diff --git a/accessible/xpcom/AccEventGen.py b/accessible/xpcom/AccEventGen.py
index 6af54c34db..8b2a46f75b 100755
--- a/accessible/xpcom/AccEventGen.py
+++ b/accessible/xpcom/AccEventGen.py
@@ -40,14 +40,14 @@ def loadEventIDL(parser, includePath, eventname):
 class Configuration:
     def __init__(self, filename):
         config = {}
-        execfile(filename, config)
+        exec(compile(open(filename, "rb").read(), filename, 'exec'), config)
         self.simple_events = config.get('simple_events', [])
 
 def firstCap(str):
     return str[0].upper() + str[1:]
 
 def writeAttributeParams(a):
-    return ("%s a%s" % (a.realtype.nativeType('in'), firstCap(a.name)))
+    return ("{} a{}".format(a.realtype.nativeType('in'), firstCap(a.name)))
 
 def print_header_file(fd, conf, incdirs):
     idl_paths = set()
@@ -64,26 +64,26 @@ def print_header_file(fd, conf, incdirs):
     for e in conf.simple_events:
         idl, idl_path = loadEventIDL(p, incdirs, e)
         idl_paths.add(idl_path)
-        for iface in filter(lambda p: p.kind == "interface", idl.productions):
+        for iface in [p for p in idl.productions if p.kind == "interface"]:
             classname = ("xpcAcc%s" % e)
             baseinterfaces = interfaces(iface)
 
-            fd.write("\nclass %s final : public %s\n" % (classname, iface.name))
+            fd.write("\nclass {} final : public {}\n".format(classname, iface.name))
             fd.write("{\n")
             fd.write("public:\n")
 
             attributes = allAttributes(iface)
-            args = map(writeAttributeParams, attributes)
-            fd.write("  %s(%s) :\n" % (classname, ", ".join(args)))
+            args = list(map(writeAttributeParams, attributes))
+            fd.write("  {}({}) :\n".format(classname, ", ".join(args)))
 
             initializers = []
             for a in attributes:
-                initializers.append("m%s(a%s)" % (firstCap(a.name), firstCap(a.name)))
+                initializers.append("m{}(a{})".format(firstCap(a.name), firstCap(a.name)))
             fd.write("  %s\n  {}\n\n" % ", ".join(initializers))
             fd.write("  NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n")
             fd.write("  NS_DECL_CYCLE_COLLECTION_CLASS(%s)\n" % (classname))
 
-            for iface in filter(lambda i: i.name != "nsISupports", baseinterfaces):
+            for iface in [i for i in baseinterfaces if i.name != "nsISupports"]:
                 fd.write("  NS_DECL_%s\n" % iface.name.upper())
 
             fd.write("\nprivate:\n")
@@ -97,13 +97,13 @@ def print_header_file(fd, conf, incdirs):
     return idl_paths
 
 def interfaceAttributeTypes(idl):
-    ifaces = filter(lambda p: p.kind == "interface", idl.productions)
+    ifaces = [p for p in idl.productions if p.kind == "interface"]
     attributes = []
     for i in ifaces:
         ifaceAttributes = allAttributes(i)
         attributes.extend(ifaceAttributes)
-    ifaceAttrs = filter(lambda a: a.realtype.nativeType("in").endswith("*"), attributes)
-    return map(lambda a: a.realtype.nativeType("in").strip(" *"), ifaceAttrs)
+    ifaceAttrs = [a for a in attributes if a.realtype.nativeType("in").endswith("*")]
+    return [a.realtype.nativeType("in").strip(" *") for a in ifaceAttrs]
 
 def print_cpp(idl, fd, conf, eventname):
     for p in idl.productions:
@@ -118,7 +118,7 @@ def print_cpp_file(fd, conf, incdirs):
     includes = []
     for e in conf.simple_events:
         if not e in includes:
-            includes.append(("nsIAccessible%s" % e))
+            includes.append("nsIAccessible%s" % e)
 
     types = []
     for e in conf.simple_events:
@@ -139,38 +139,38 @@ def print_cpp_file(fd, conf, incdirs):
 
 def attributeVariableTypeAndName(a):
     if a.realtype.nativeType('in').endswith('*'):
-        l = ["nsCOMPtr<%s> m%s;" % (a.realtype.nativeType('in').strip('* '),
+        l = ["nsCOMPtr<{}> m{};".format(a.realtype.nativeType('in').strip('* '),
                    firstCap(a.name))]
     elif a.realtype.nativeType('in').count("nsAString"):
         l = ["nsString m%s;" % firstCap(a.name)]
     elif a.realtype.nativeType('in').count("nsACString"):
         l = ["nsCString m%s;" % firstCap(a.name)]
     else:
-        l = ["%sm%s;" % (a.realtype.nativeType('in'),
+        l = ["{}m{};".format(a.realtype.nativeType('in'),
                        firstCap(a.name))]
     return ", ".join(l)
 
 def writeAttributeGetter(fd, classname, a):
     fd.write("NS_IMETHODIMP\n")
-    fd.write("%s::Get%s(" % (classname, firstCap(a.name)))
+    fd.write("{}::Get{}(".format(classname, firstCap(a.name)))
     if a.realtype.nativeType('in').endswith('*'):
-        fd.write("%s** a%s" % (a.realtype.nativeType('in').strip('* '), firstCap(a.name)))
+        fd.write("{}** a{}".format(a.realtype.nativeType('in').strip('* '), firstCap(a.name)))
     elif a.realtype.nativeType('in').count("nsAString"):
         fd.write("nsAString& a%s" % firstCap(a.name))
     elif a.realtype.nativeType('in').count("nsACString"):
         fd.write("nsACString& a%s" % firstCap(a.name))
     else:
-        fd.write("%s*a%s" % (a.realtype.nativeType('in'), firstCap(a.name)))
+        fd.write("{}*a{}".format(a.realtype.nativeType('in'), firstCap(a.name)))
     fd.write(")\n");
     fd.write("{\n");
     if a.realtype.nativeType('in').endswith('*'):
-        fd.write("  NS_IF_ADDREF(*a%s = m%s);\n" % (firstCap(a.name), firstCap(a.name)))
+        fd.write("  NS_IF_ADDREF(*a{} = m{});\n".format(firstCap(a.name), firstCap(a.name)))
     elif a.realtype.nativeType('in').count("nsAString"):
-        fd.write("  a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name)))
+        fd.write("  a{} = m{};\n".format(firstCap(a.name), firstCap(a.name)))
     elif a.realtype.nativeType('in').count("nsACString"):
-        fd.write("  a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name)))
+        fd.write("  a{} = m{};\n".format(firstCap(a.name), firstCap(a.name)))
     else:
-        fd.write("  *a%s = m%s;\n" % (firstCap(a.name), firstCap(a.name)))
+        fd.write("  *a{} = m{};\n".format(firstCap(a.name), firstCap(a.name)))
     fd.write("  return NS_OK;\n");
     fd.write("}\n\n");
 
@@ -186,7 +186,7 @@ def interfaces(iface):
 def allAttributes(iface):
     attributes = []
     for i in interfaces(iface):
-        attrs = filter(lambda m: isinstance(m, xpidl.Attribute), i.members)
+        attrs = [m for m in i.members if isinstance(m, xpidl.Attribute)]
         attributes.extend(attrs)
 
     return attributes
@@ -194,7 +194,7 @@ def allAttributes(iface):
 def write_cpp(eventname, iface, fd):
     classname = "xpcAcc%s" % eventname
     attributes = allAttributes(iface)
-    ccattributes = filter(lambda m: m.realtype.nativeType('in').endswith('*'), attributes)
+    ccattributes = [m for m in attributes if m.realtype.nativeType('in').endswith('*')]
     fd.write("NS_IMPL_CYCLE_COLLECTION(%s" % classname)
     for c in ccattributes:
         fd.write(", m%s" % firstCap(c.name))
diff --git a/build/appini_header.py b/build/appini_header.py
index 356a0692e7..f87adf30d4 100644
--- a/build/appini_header.py
+++ b/build/appini_header.py
@@ -5,11 +5,11 @@
 '''Parses a given application.ini file and outputs the corresponding
    XULAppData structure as a C++ header file'''
 
-import ConfigParser
+import configparser
 import sys
 
 def main(output, file):
-    config = ConfigParser.RawConfigParser()
+    config = configparser.RawConfigParser()
     config.read(file)
     flags = set()
     try:
@@ -20,15 +20,14 @@ def main(output, file):
         if config.getint('Crash Reporter', 'Enabled') == 1:
             flags.add('NS_XRE_ENABLE_CRASH_REPORTER')
     except: pass
-    appdata = dict(("%s:%s" % (s, o), config.get(s, o)) for s in config.sections() for o in config.options(s))
+    appdata = {"{}:{}".format(s, o): config.get(s, o) for s in config.sections() for o in config.options(s)}
     appdata['flags'] = ' | '.join(flags) if flags else '0'
     appdata['App:profile'] = '"%s"' % appdata['App:profile'] if 'App:profile' in appdata else 'NULL'
     expected = ('App:vendor', 'App:name', 'App:remotingname', 'App:version', 'App:buildid',
                 'App:id', 'Gecko:minversion', 'Gecko:maxversion')
     missing = [var for var in expected if var not in appdata]
     if missing:
-        print >>sys.stderr, \
-            "Missing values in %s: %s" % (file, ', '.join(missing))
+        print("Missing values in {}: {}".format(file, ', '.join(missing)), file=sys.stderr)
         sys.exit(1)
 
     if not 'Crash Reporter:serverurl' in appdata:
@@ -57,4 +56,4 @@ if __name__ == '__main__':
     if len(sys.argv) != 1:
         main(sys.stdout, sys.argv[1])
     else:
-        print >>sys.stderr, "Usage: %s /path/to/application.ini" % sys.argv[0]
+        print("Usage: %s /path/to/application.ini" % sys.argv[0], file=sys.stderr)
diff --git a/build/build-clang/build-clang.py b/build/build-clang/build-clang.py
index 697bbb9b8b..30ac7f5ec7 100755
--- a/build/build-clang/build-clang.py
+++ b/build/build-clang/build-clang.py
@@ -34,7 +34,7 @@ def symlink(source, link_name):
 def check_run(args):
     global DEBUG
     if DEBUG:
-        print >> sys.stderr, ' '.join(args)
+        print(' '.join(args), file=sys.stderr)
     r = subprocess.call(args)
     assert r == 0
 
@@ -43,11 +43,11 @@ def run_in(path, args):
     d = os.getcwd()
     global DEBUG
     if DEBUG:
-        print >> sys.stderr, 'cd "%s"' % path
+        print('cd "%s"' % path, file=sys.stderr)
     os.chdir(path)
     check_run(args)
     if DEBUG:
-        print >> sys.stderr, 'cd "%s"' % d
+        print('cd "%s"' % d, file=sys.stderr)
     os.chdir(d)
 
 
@@ -93,7 +93,7 @@ def build_tar_package(tar, name, base, directory):
 def copy_dir_contents(src, dest):
     for f in glob.glob("%s/*" % src):
         try:
-            destname = "%s/%s" % (dest, os.path.basename(f))
+            destname = "{}/{}".format(dest, os.path.basename(f))
             if os.path.isdir(f):
                 shutil.copytree(f, destname)
             else:
@@ -378,7 +378,7 @@ if __name__ == "__main__":
         extra_cxxflags2 = ["-fPIC", "-static-libstdc++"]
 
         if os.environ.has_key('LD_LIBRARY_PATH'):
-            os.environ['LD_LIBRARY_PATH'] = '%s/lib64/:%s' % (gcc_dir, os.environ['LD_LIBRARY_PATH']);
+            os.environ['LD_LIBRARY_PATH'] = '{}/lib64/:{}'.format(gcc_dir, os.environ['LD_LIBRARY_PATH']);
         else:
             os.environ['LD_LIBRARY_PATH'] = '%s/lib64/' % gcc_dir
     elif is_windows():
diff --git a/build/checksums.py b/build/checksums.py
index 9b13b50cb4..abecbe5b6a 100755
--- a/build/checksums.py
+++ b/build/checksums.py
@@ -81,9 +81,9 @@ def process_files(files, output_filename, digests, strip):
                         short_file = short_file.lstrip('/')
                     else:
                         short_file = file
-                    print >>output, '%s %s %s %s' % (hash, digest,
+                    print('%s %s %s %s' % (hash, digest,
                                                      os.path.getsize(file),
-                                                     short_file)
+                                                     short_file), file=output)
 
 def setup_logging(level=logging.DEBUG):
     '''This function sets up the logging module using a speficiable logging
@@ -140,7 +140,7 @@ def main():
     try:
         for digest in options.digests:
             hashlib.new(digest)
-    except ValueError, ve:
+    except ValueError as ve:
         logger.error('Could not create a "%s" hash object (%s)' %
                      (digest, ve.args[0]))
         exit(1)
diff --git a/build/compare-mozconfig/compare-mozconfigs-wrapper.py b/build/compare-mozconfig/compare-mozconfigs-wrapper.py
index e1888eed7e..0950b0231d 100644
--- a/build/compare-mozconfig/compare-mozconfigs-wrapper.py
+++ b/build/compare-mozconfig/compare-mozconfigs-wrapper.py
@@ -3,7 +3,6 @@
 # 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 unicode_literals
 
 import logging
 import mozunit
diff --git a/build/compare-mozconfig/compare-mozconfigs.py b/build/compare-mozconfig/compare-mozconfigs.py
index 876e336fe5..d5422f3c50 100644
--- a/build/compare-mozconfig/compare-mozconfigs.py
+++ b/build/compare-mozconfig/compare-mozconfigs.py
@@ -5,13 +5,12 @@
 
 # originally from http://hg.mozilla.org/build/tools/file/4ab9c1a4e05b/scripts/release/compare-mozconfigs.py
 
-from __future__ import unicode_literals
 
 import logging
 import os
 import site
 import sys
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import difflib
 
 FAILURE_CODE = 1
@@ -26,7 +25,7 @@ def make_hg_url(hgHost, repoPath, protocol='https', revision=None,
                 filename=None):
     """construct a valid hg url from a base hg url (hg.mozilla.org),
     repoPath, revision and possible filename"""
-    base = '%s://%s' % (protocol, hgHost)
+    base = '{}://{}'.format(protocol, hgHost)
     repo = '/'.join(p.strip('/') for p in [base, repoPath])
     if not filename:
         if not revision:
@@ -40,15 +39,15 @@ def make_hg_url(hgHost, repoPath, protocol='https', revision=None,
 
 def readConfig(configfile, keys=[], required=[]):
     c = {}
-    execfile(configfile, c)
+    exec(compile(open(configfile, "rb").read(), configfile, 'exec'), c)
     for k in keys:
         c = c[k]
-    items = c.keys()
+    items = list(c.keys())
     err = False
     for key in required:
         if key not in items:
             err = True
-            log.error("Required item `%s' missing from %s" % (key, c))
+            log.error("Required item `{}' missing from {}".format(key, c))
     if err:
         raise ConfigError("Missing at least one item in config, see above")
     return c
@@ -100,7 +99,7 @@ def verify_mozconfigs(mozconfig_pair, nightly_mozconfig_pair, platform,
                             mozconfigWhitelist['nightly'][platform]:
                         continue
                     else:
-                        log.warning("%s not in %s %s!" % (
+                        log.warning("{} not in {} {}!".format(
                             clean_line, platform,
                             mozconfigWhitelist['nightly'][platform]))
             else:
@@ -122,11 +121,11 @@ def get_mozconfig(path, options):
     specified should be relative to the root of the hg
     repository e.g browser/config/mozconfigs/linux32/nightly"""
     if options.no_download:
-        return open(path, 'r').readlines()
+        return open(path).readlines()
     else:
         url = make_hg_url(options.hghost, options.branch, 'http',
                     options.revision, path)
-        return urllib2.urlopen(url).readlines()
+        return six.moves.urllib.request.urlopen(url).readlines()
 
 if __name__ == '__main__':
     from optparse import OptionParser
diff --git a/build/gen_test_packages_manifest.py b/build/gen_test_packages_manifest.py
index 1e2a7c3bba..4160774196 100644
--- a/build/gen_test_packages_manifest.py
+++ b/build/gen_test_packages_manifest.py
@@ -68,7 +68,7 @@ def generate_package_data(args):
     tests_common = args.tests_common
     jsshell = args.jsshell
 
-    harness_requirements = dict([(k, [tests_common]) for k in ALL_HARNESSES])
+    harness_requirements = {k: [tests_common] for k in ALL_HARNESSES}
     harness_requirements['jittest'].append(jsshell)
     for harness in PACKAGE_SPECIFIED_HARNESSES + OPTIONAL_PACKAGES:
         pkg_name = getattr(args, harness, None)
diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py
index 22eaa3425a..f393c8f320 100644
--- a/build/mach_bootstrap.py
+++ b/build/mach_bootstrap.py
@@ -2,7 +2,6 @@
 # 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 print_function, unicode_literals
 
 import errno
 import json
@@ -12,7 +11,7 @@ import random
 import subprocess
 import sys
 import uuid
-import __builtin__
+import builtins
 
 from types import ModuleType
 
@@ -41,7 +40,7 @@ SEARCH_PATHS = [
     'python/blessings',
     'python/compare-locales',
     'python/configobj',
-    'python/futures',
+    # 'python/futures',  # Python 3 has concurrent.futures built-in
     'python/jsmin',
     'python/psutil',
     'python/pylru',
@@ -173,9 +172,9 @@ def bootstrap(topsrcdir, mozilla_dir=None):
     # Ensure we are running Python 2.7+. We put this check here so we generate a
     # user-friendly error message rather than a cryptic stack trace on module
     # import.
-    if sys.version_info[0] != 2 or sys.version_info[1] < 7:
-        print('Python 2.7 or above (but not Python 3) is required to run mach.')
-        print('You are running Python', platform.python_version())
+    if sys.version_info[0] < 3:
+        print('Python 3 is required to run mach.')
+        print(('You are running Python', platform.python_version()))
         sys.exit(1)
 
     # Global build system and mach state is stored in a central directory. By
@@ -233,10 +232,14 @@ def bootstrap(topsrcdir, mozilla_dir=None):
         ))
 
         if platform.system() == 'Linux':
-            dist = list(platform.linux_distribution())
+            try:
+                import distro
+                dist = [distro.name(), distro.version(), distro.codename()]
+            except ImportError:
+                dist = ['', '', '']
             data['system']['linux_distribution'] = dist
         elif platform.system() == 'Windows':
-            win32_ver=list((platform.win32_ver())),
+            win32_ver=list(platform.win32_ver()),
             data['system']['win32_ver'] = win32_ver
         elif platform.system() == 'Darwin':
             # mac version is a special Cupertino snowflake
@@ -350,7 +353,7 @@ def bootstrap(topsrcdir, mozilla_dir=None):
 # and caveats.
 # Objdirs outside the source directory are ignored because in most cases, if
 # a .pyc/.pyo file exists there, a .py file will be next to it anyways.
-class ImportHook(object):
+class ImportHook:
     def __init__(self, original_import):
         self._original_import = original_import
         # Assume the source directory is the parent directory of the one
@@ -360,7 +363,7 @@ class ImportHook(object):
         self._modules = set()
 
     def __call__(self, name, globals=None, locals=None, fromlist=None,
-                 level=-1):
+                 level=0):
         # name might be a relative import. Instead of figuring out what that
         # resolves to, which is complex, just rely on the real import.
         # Since we don't know the full module name, we can't check sys.modules,
@@ -409,4 +412,4 @@ class ImportHook(object):
 
 
 # Install our hook
-__builtin__.__import__ = ImportHook(__builtin__.__import__)
+builtins.__import__ = ImportHook(builtins.__import__)
diff --git a/build/moz.configure/init.configure b/build/moz.configure/init.configure
index 7869764870..79ba7a8e68 100644
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -133,7 +133,7 @@ option(env='PYTHON', nargs=1, help='Python interpreter')
 @imports(_from='mozbuild.configure.util', _import='LineIO')
 @imports(_from='mozbuild.virtualenv', _import='VirtualenvManager')
 @imports(_from='mozbuild.virtualenv', _import='verify_python_version')
-@imports('distutils.sysconfig')
+@imports('sysconfig')
 def virtualenv_python(env_python, build_env, mozconfig, help):
     if help:
         return
@@ -193,7 +193,7 @@ def virtualenv_python(env_python, build_env, mozconfig, help):
         sys.exit(subprocess.call([python] + sys.argv))
 
     # We are now in the virtualenv
-    if not distutils.sysconfig.get_python_lib():
+    if not sysconfig.get_path('purelib'):
         die('Could not determine python site packages directory')
 
     return python
@@ -212,7 +212,7 @@ def early_options():
     def early_options():
         return set(
             option.env
-            for option in __sandbox__._options.itervalues()
+            for option in __sandbox__._options.values()
             if option.env
         )
     return early_options
@@ -240,17 +240,17 @@ def mozconfig_options(mozconfig, help):
                 log.info('  %s' % arg)
                 helper.add(arg, origin='mozconfig', args=helper._args)
 
-        for key, value in mozconfig['env']['added'].iteritems():
+        for key, value in mozconfig['env']['added'].items():
             add(key, value)
             os.environ[key] = value
-        for key, (_, value) in mozconfig['env']['modified'].iteritems():
+        for key, (_, value) in mozconfig['env']['modified'].items():
             add(key, value)
             os.environ[key] = value
-        for key, value in mozconfig['vars']['added'].iteritems():
+        for key, value in mozconfig['vars']['added'].items():
             # mozconfig_loader adds _IS_SET variables that are irrelevant
             if not key.endswith('_IS_SET'):
                 add(key, value)
-        for key, (_, value) in mozconfig['vars']['modified'].iteritems():
+        for key, (_, value) in mozconfig['vars']['modified'].items():
             add(key, value)
 
 
@@ -400,7 +400,12 @@ def split_triplet(triplet):
 def config_sub(shell, triplet):
     config_sub = os.path.join(os.path.dirname(__file__), '..',
                               'autoconf', 'config.sub')
-    return subprocess.check_output([shell, config_sub, triplet]).strip()
+    result = subprocess.check_output([shell, config_sub, triplet]).strip()
+    try:
+        result = result.decode('utf-8')
+    except AttributeError:
+        pass
+    return result
 
 
 @depends('--host', shell)
@@ -411,6 +416,10 @@ def host(value, shell):
         config_guess = os.path.join(os.path.dirname(__file__), '..',
                                     'autoconf', 'config.guess')
         host = subprocess.check_output([shell, config_guess]).strip()
+        try:
+            host = host.decode('utf-8')
+        except AttributeError:
+            pass
     else:
         host = value[0]
 
@@ -761,7 +770,7 @@ def enabled_in_nightly(milestone, _):
 def all_configure_options(_):
     result = []
     previous = None
-    for option in __sandbox__._options.itervalues():
+    for option in __sandbox__._options.values():
         # __sandbox__._options contains items for both option.name and
         # option.env. But it's also an OrderedDict, meaning both are
         # consecutive.
diff --git a/build/moz.configure/old.configure b/build/moz.configure/old.configure
index e08d093080..ba9200172e 100644
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -79,7 +79,7 @@ def prepare_configure(old_configure, mozconfig, awk, m4, build_env, shell,
 
         # Make old-configure append to config.log, where we put our own log.
         # This could be done with a m4 macro, but it's way easier this way
-        script = script.replace('>./config.log', '>>./config.log')
+        script = script.replace(b'>./config.log', b'>>./config.log')
 
         with open(old_configure, 'wb') as fh:
             fh.write(script)
@@ -346,7 +346,7 @@ def old_configure(prepare_configure, extra_old_configure_args, all_options,
         # Every variation of the exec() function I tried led to:
         # SyntaxError: unqualified exec is not allowed in function 'main' it
         # contains a nested function with free variables
-        exec code in raw_config
+        exec(code, raw_config)
 
     # Ensure all the flags known to old-configure appear in the
     # @old_configure_options above.
@@ -380,9 +380,9 @@ def set_old_configure_define(name, value):
 def post_old_configure(raw_config):
     for k, v in raw_config['substs']:
         set_old_configure_config(
-            k[1:-1], v[1:-1] if isinstance(v, types.StringTypes) else v)
+            k[1:-1], v[1:-1] if isinstance(v, str) else v)
 
-    for k, v in dict(raw_config['defines']).iteritems():
+    for k, v in dict(raw_config['defines']).items():
         set_old_configure_define(k[1:-1], v[1:-1])
 
     set_old_configure_config('non_global_defines',
diff --git a/build/moz.configure/toolchain.configure b/build/moz.configure/toolchain.configure
index de45e74744..04b7bc4ba7 100644
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -236,7 +236,7 @@ def get_compiler_info(compiler, language):
         ('CPU', CPU_preprocessor_checks),
         ('KERNEL', kernel_preprocessor_checks),
     ):
-        for n, (value, condition) in enumerate(preprocessor_checks.iteritems()):
+        for n, (value, condition) in enumerate(preprocessor_checks.items()):
             check += dedent('''\
                 #%(if)s %(condition)s
                 %%%(name)s "%(value)s"
@@ -269,7 +269,7 @@ def get_compiler_info(compiler, language):
     # have non-ASCII characters. Treat the output as bytearray.
     data = {}
     for line in result.splitlines():
-        if line.startswith(b'%'):
+        if line.startswith('%'):
             k, _, v = line.partition(' ')
             k = k.lstrip('%')
             data[k] = v.replace(' ', '').lstrip('"').rstrip('"')
@@ -601,7 +601,7 @@ def compiler(language, host_or_target, c_compiler=None, other_compiler=None,
             if cross_compiling and other_compiler.type == 'clang':
                 return namespace(**{
                     k: [] if k == 'flags' else v
-                    for k, v in other_compiler.__dict__.iteritems()
+                    for k, v in other_compiler.__dict__.items()
                 })
 
     # Normally, we'd use `var` instead of `_var`, but the interaction with
diff --git a/build/moz.configure/util.configure b/build/moz.configure/util.configure
index 6bb97574c2..4860c339de 100644
--- a/build/moz.configure/util.configure
+++ b/build/moz.configure/util.configure
@@ -35,6 +35,10 @@ def check_cmd_output(*args, **kwargs):
         stdout, stderr = proc.communicate()
         retcode = proc.wait()
         if retcode == 0:
+            try:
+                stdout = stdout.decode('utf-8', errors='replace')
+            except AttributeError:
+                pass
             return stdout
 
         log.debug('The command returned non-zero exit status %d.',
diff --git a/build/pgo/genpgocert.py b/build/pgo/genpgocert.py
index c58bcd40d6..30f4aa2e1a 100644
--- a/build/pgo/genpgocert.py
+++ b/build/pgo/genpgocert.py
@@ -21,9 +21,9 @@ from mozfile import NamedTemporaryFile
 from mozprofile.permissions import ServerLocations
 
 dbFiles = [
-  re.compile("^cert[0-9]+\.db$"),
-  re.compile("^key[0-9]+\.db$"),
-  re.compile("^secmod\.db$")
+  re.compile(r"^cert[0-9]+\.db$"),
+  re.compile(r"^key[0-9]+\.db$"),
+  re.compile(r"^secmod\.db$")
 ]
 
 def unlinkDbFiles(path):
@@ -48,7 +48,7 @@ def runUtil(util, args, inputdata = None):
     pathvar = "LD_LIBRARY_PATH"
     app_path = os.path.dirname(util)
     if pathvar in env:
-      env[pathvar] = "%s%s%s" % (app_path, os.pathsep, env[pathvar])
+      env[pathvar] = "{}{}{}".format(app_path, os.pathsep, env[pathvar])
     else:
       env[pathvar] = app_path
   proc = subprocess.Popen([util] + args, env=env,
@@ -58,7 +58,7 @@ def runUtil(util, args, inputdata = None):
 
 
 def createRandomFile(randomFile):
-  for count in xrange(0, 2048):
+  for count in range(0, 2048):
     randomFile.write(chr(random.randint(0, 255)))
 
 
@@ -125,14 +125,14 @@ def createSSLServerCertificate(build, srcDir):
     iterator = iter(locations)
 
     # Skips the first entry, I don't know why: bug 879740
-    iterator.next()
+    next(iterator)
 
     locationsParam = ""
     firstLocation = ""
     for loc in iterator:
       if loc.scheme == "https" and "nocert" not in loc.options:
         customCertOption = False
-        customCertRE = re.compile("^cert=(?:\w+)")
+        customCertRE = re.compile(r"^cert=(?:\w+)")
         for option in loc.options:
           match = customCertRE.match(option)
           if match:
@@ -148,7 +148,7 @@ def createSSLServerCertificate(build, srcDir):
             firstLocation = loc.host
 
     if not firstLocation:
-      print "Nothing to generate, no automatic secure hosts specified"
+      print("Nothing to generate, no automatic secure hosts specified")
     else:
       createRandomFile(rndfile)
 
@@ -162,7 +162,7 @@ def createSSLServerCertificate(build, srcDir):
   return 0
 
 if len(sys.argv) == 1:
-  print "Specify --gen-server or --gen-ca"
+  print("Specify --gen-server or --gen-ca")
   sys.exit(1)
 
 build = MozbuildObject.from_environment()
@@ -170,23 +170,23 @@ certdir = os.path.join(build.topsrcdir, "build", "pgo", "certs")
 if sys.argv[1] == "--gen-server":
   certificateStatus = createSSLServerCertificate(build, certdir)
   if certificateStatus:
-    print "TEST-UNEXPECTED-FAIL | SSL Server Certificate generation"
+    print("TEST-UNEXPECTED-FAIL | SSL Server Certificate generation")
 
   sys.exit(certificateStatus)
 
 if sys.argv[1] == "--gen-ca":
   certificateStatus = createCertificateAuthority(build, certdir)
   if certificateStatus:
-    print "TEST-UNEXPECTED-FAIL | Certificate Authority generation"
+    print("TEST-UNEXPECTED-FAIL | Certificate Authority generation")
   else:
-    print "\n\n"
-    print "==================================================="
-    print " IMPORTANT:"
-    print " To use this new certificate authority in tests"
-    print " run 'make' at testing/mochitest"
-    print "==================================================="
+    print("\n\n")
+    print("===================================================")
+    print(" IMPORTANT:")
+    print(" To use this new certificate authority in tests")
+    print(" run 'make' at testing/mochitest")
+    print("===================================================")
 
   sys.exit(certificateStatus)
 
-print "Invalid option specified"
+print("Invalid option specified")
 sys.exit(1)
diff --git a/build/pgo/profileserver.py b/build/pgo/profileserver.py
index adc93d9b13..34416f72e8 100644
--- a/build/pgo/profileserver.py
+++ b/build/pgo/profileserver.py
@@ -63,7 +63,7 @@ if __name__ == '__main__':
 
             vcdir = os.path.abspath(os.path.join(env[e], '../../VC/bin'))
             if os.path.exists(vcdir):
-                env['PATH'] = '%s;%s' % (vcdir, env['PATH'])
+                env['PATH'] = '{};{}'.format(vcdir, env['PATH'])
                 break
 
     # Run Firefox a first time to initialize its profile
@@ -77,7 +77,7 @@ if __name__ == '__main__':
     jarlog = os.getenv("JARLOG_FILE")
     if jarlog:
       env["MOZ_JAR_LOG_FILE"] = os.path.abspath(jarlog)
-      print "jarlog: %s" % env["MOZ_JAR_LOG_FILE"]
+      print("jarlog: %s" % env["MOZ_JAR_LOG_FILE"])
 
     cmdargs = ["http://localhost:%d/index.html" % PORT]
     runner = FirefoxRunner(profile=profile,
diff --git a/build/ppCheck.py b/build/ppCheck.py
index 1e27ca1715..f072720bfa 100644
--- a/build/ppCheck.py
+++ b/build/ppCheck.py
@@ -1,9 +1,8 @@
 #!/usr/bin/env python
 
-from __future__ import print_function
 import os, sys
 
-if not len(sys.argv) is 2 or not os.path.exists(sys.argv[1]):
+if not len(sys.argv) == 2 or not os.path.exists(sys.argv[1]):
   print("\nYou did not supply a valid path to check.")
   exit(1)
 else:
@@ -65,7 +64,7 @@ PP_BAD_FILES = list(dict.fromkeys(PP_BAD_FILES))
 print('Done!')
 
 if len(PP_BAD_FILES) > 0:
-  print("\nWARNING: The following {0} file(s) in {1} may require preprocessing:\n".format(len(PP_BAD_FILES), DIST_PATH))
+  print("\nWARNING: The following {} file(s) in {} may require preprocessing:\n".format(len(PP_BAD_FILES), DIST_PATH))
   for file in PP_BAD_FILES:
     print(file)
 
diff --git a/build/pymake/mkformat.py b/build/pymake/mkformat.py
index 41dd761b2f..29e0407e47 100755
--- a/build/pymake/mkformat.py
+++ b/build/pymake/mkformat.py
@@ -6,8 +6,8 @@ import pymake.parser
 filename = sys.argv[1]
 source = None
 
-with open(filename, 'rU') as fh:
+with open(filename) as fh:
     source = fh.read()
 
 statements = pymake.parser.parsestring(source, filename)
-print statements.to_source()
+print(statements.to_source())
diff --git a/build/pymake/mkparse.py b/build/pymake/mkparse.py
index 253683948a..aa94b81bab 100755
--- a/build/pymake/mkparse.py
+++ b/build/pymake/mkparse.py
@@ -4,9 +4,9 @@ import sys
 import pymake.parser
 
 for f in sys.argv[1:]:
-    print "Parsing %s" % f
-    fd = open(f, 'rU')
+    print("Parsing %s" % f)
+    fd = open(f)
     s = fd.read()
     fd.close()
     stmts = pymake.parser.parsestring(s, f)
-    print stmts
+    print(stmts)
diff --git a/build/pymake/pymake/builtins.py b/build/pymake/pymake/builtins.py
index eb6f2e11bd..1ab3328195 100644
--- a/build/pymake/pymake/builtins.py
+++ b/build/pymake/pymake/builtins.py
@@ -2,7 +2,7 @@
 import errno, sys, os, shutil, time
 from getopt import getopt, GetoptError
 
-from process import PythonException
+from .process import PythonException
 
 __all__ = ["mkdir", "rm", "sleep", "touch"]
 
@@ -13,8 +13,8 @@ def mkdir(args):
   """
   try:
     opts, args = getopt(args, "p", ["parents"])
-  except GetoptError, e:
-    raise PythonException, ("mkdir: %s" % e, 1)
+  except GetoptError as e:
+    raise PythonException("mkdir: %s" % e, 1)
   parents = False
   for o, a in opts:
     if o in ('-p', '--parents'):
@@ -25,11 +25,11 @@ def mkdir(args):
         os.makedirs(f)
       else:
         os.mkdir(f)
-    except OSError, e:
+    except OSError as e:
       if e.errno == errno.EEXIST and parents:
         pass
       else:
-        raise PythonException, ("mkdir: %s" % e, 1)
+        raise PythonException("mkdir: %s" % e, 1)
 
 def rm(args):
   """
@@ -38,8 +38,8 @@ def rm(args):
   """
   try:
     opts, args = getopt(args, "rRf", ["force", "recursive"])
-  except GetoptError, e:
-    raise PythonException, ("rm: %s" % e, 1)
+  except GetoptError as e:
+    raise PythonException("rm: %s" % e, 1)
   force = False
   recursive = False
   for o, a in opts:
@@ -50,7 +50,7 @@ def rm(args):
   for f in args:
     if os.path.isdir(f):
       if not recursive:
-        raise PythonException, ("rm: cannot remove '%s': Is a directory" % f, 1)
+        raise PythonException("rm: cannot remove '%s': Is a directory" % f, 1)
       else:
         shutil.rmtree(f, force)
     elif os.path.exists(f):
@@ -58,9 +58,9 @@ def rm(args):
         os.unlink(f)
       except:
         if not force:
-          raise PythonException, ("rm: failed to remove '%s': %s" % (f, sys.exc_info()[0]), 1)
+          raise PythonException("rm: failed to remove '{}': {}".format(f, sys.exc_info()[0]), 1)
     elif not force:
-      raise PythonException, ("rm: cannot remove '%s': No such file or directory" % f, 1)
+      raise PythonException("rm: cannot remove '%s': No such file or directory" % f, 1)
 
 def sleep(args):
     """
@@ -70,7 +70,7 @@ def sleep(args):
     values = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
     for a in args:
         multiplier = 1
-        for k, v in values.iteritems():
+        for k, v in values.items():
             if a.endswith(k):
                 a = a[:-1]
                 multiplier = v
@@ -79,7 +79,7 @@ def sleep(args):
             f = float(a)
             total += f * multiplier
         except ValueError:
-            raise PythonException, ("sleep: invalid time interval '%s'" % a, 1)
+            raise PythonException("sleep: invalid time interval '%s'" % a, 1)
     time.sleep(total)
 
 def touch(args):
@@ -88,16 +88,16 @@ def touch(args):
     """
     try:
         opts, args = getopt(args, "t:")
-    except GetoptError, e:
-        raise PythonException, ("touch: %s" % e, 1)
+    except GetoptError as e:
+        raise PythonException("touch: %s" % e, 1)
     opts = dict(opts)
     times = None
     if '-t' in opts:
         import re
         from time import mktime, localtime
-        m = re.match('^(?P<Y>(?:\d\d)?\d\d)?(?P<M>\d\d)(?P<D>\d\d)(?P<h>\d\d)(?P<m>\d\d)(?:\.(?P<s>\d\d))?$', opts['-t'])
+        m = re.match(r'^(?P<Y>(?:\d\d)?\d\d)?(?P<M>\d\d)(?P<D>\d\d)(?P<h>\d\d)(?P<m>\d\d)(?:\.(?P<s>\d\d))?$', opts['-t'])
         if not m:
-            raise PythonException, ("touch: invalid date format '%s'" % opts['-t'], 1)
+            raise PythonException("touch: invalid date format '%s'" % opts['-t'], 1)
         def normalized_field(m, f):
             if f == 'Y':
                 if m.group(f) is None:
diff --git a/build/pymake/pymake/command.py b/build/pymake/pymake/command.py
index cd68e4fdb2..3d18a2cc12 100644
--- a/build/pymake/pymake/command.py
+++ b/build/pymake/pymake/command.py
@@ -62,7 +62,7 @@ def parsemakeflags(env):
     return opts
 
 def _version(*args):
-    print """pymake: GNU-compatible make program
+    print("""pymake: GNU-compatible make program
 Copyright (C) 2009 The Mozilla Foundation <http://www.mozilla.org/>
 This is free software; see the source for copying conditions.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
@@ -71,7 +71,7 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE."""
+DEALINGS IN THE SOFTWARE.""")
 
 _log = logging.getLogger('pymake.execution')
 
@@ -95,7 +95,7 @@ class _MakeContext(object):
 
     def remakecb(self, remade, error=None):
         if error is not None:
-            print error
+            print(error)
             self.context.defer(self.cb, 2)
             return
 
@@ -124,15 +124,15 @@ class _MakeContext(object):
                     self.makefile.include(f)
                 self.makefile.finishparsing()
                 self.makefile.remakemakefiles(self.remakecb)
-            except util.MakeError, e:
-                print e
+            except util.MakeError as e:
+                print(e)
                 self.context.defer(self.cb, 2)
 
             return
 
         if len(self.targets) == 0:
             if self.makefile.defaulttarget is None:
-                print "No target specified and no default target found."
+                print("No target specified and no default target found.")
                 self.context.defer(self.cb, 2)
                 return
 
@@ -154,7 +154,7 @@ class _MakeContext(object):
 
         if not len(self.realtargets):
             if self.options.printdir:
-                print "make.py[%i]: Leaving directory '%s'" % (self.makelevel, self.workdir)
+                print("make.py[%i]: Leaving directory '%s'" % (self.makelevel, self.workdir))
             sys.stdout.flush()
 
             self.context.defer(self.cb, 0)
@@ -255,24 +255,24 @@ def main(args, env, cwd, cb):
         context = process.getcontext(options.jobcount)
 
         if options.printdir:
-            print "make.py[%i]: Entering directory '%s'" % (makelevel, workdir)
+            print("make.py[%i]: Entering directory '%s'" % (makelevel, workdir))
             sys.stdout.flush()
 
         if len(options.makefiles) == 0:
             if os.path.exists(util.normaljoin(workdir, 'Makefile')):
                 options.makefiles.append('Makefile')
             else:
-                print "No makefile found"
+                print("No makefile found")
                 cb(2)
                 return
 
         ostmts, targets, overrides = parserdata.parsecommandlineargs(arguments)
 
         _MakeContext(makeflags, makelevel, workdir, context, env, targets, options, ostmts, overrides, cb)
-    except (util.MakeError), e:
-        print e
+    except (util.MakeError) as e:
+        print(e)
         if options.printdir:
-            print "make.py[%i]: Leaving directory '%s'" % (makelevel, workdir)
+            print("make.py[%i]: Leaving directory '%s'" % (makelevel, workdir))
         sys.stdout.flush()
         cb(2)
         return
diff --git a/build/pymake/pymake/data.py b/build/pymake/pymake/data.py
index dcd7e92258..fc67e91d0f 100644
--- a/build/pymake/pymake/data.py
+++ b/build/pymake/pymake/data.py
@@ -3,13 +3,11 @@ A representation of makefile data structures.
 """
 
 import logging, re, os, sys
-import parserdata, parser, functions, process, util, implicit
+from . import parserdata, parser, functions, process, util, implicit
 from cStringIO import StringIO
+from functools import reduce
 
-if sys.version_info[0] < 3:
-    str_type = basestring
-else:
-    str_type = str
+str_type = str
 
 _log = logging.getLogger('pymake.data')
 
@@ -69,7 +67,7 @@ def _if_else(c, t, f):
     return f()
 
 
-class BaseExpansion(object):
+class BaseExpansion:
     """Base class for expansions.
 
     A make expansion is the parsed representation of a string, which may
@@ -95,8 +93,7 @@ class BaseExpansion(object):
         child expansions and extract all functions in the tree.
         """
         # An empty generator. Yeah, it's weird.
-        for x in []:
-            yield x
+        yield from []
 
     def variable_references(self, descend=False):
         """Obtain all variable references in this expansion.
@@ -186,7 +183,7 @@ class StringExpansion(BaseExpansion):
         return self.s, False
 
     def __repr__(self):
-        return "Exp<%s>(%r)" % (self.loc, self.s)
+        return "Exp<{}>({!r})".format(self.loc, self.s)
 
     def __eq__(self, other):
         """We only compare the string contents."""
@@ -355,11 +352,10 @@ class Expansion(BaseExpansion, list):
 
             if descend:
                 for exp in e.expansions(descend=True):
-                    for f in exp.functions(descend=True):
-                        yield f
+                    yield from exp.functions(descend=True)
 
     def __repr__(self):
-        return "<Expansion with elements: %r>" % ([e for e, isfunc in self],)
+        return "<Expansion with elements: {!r}>".format([e for e, isfunc in self])
 
     def to_source(self, escape_variables=False, escape_comments=False):
         parts = []
@@ -405,7 +401,7 @@ class Expansion(BaseExpansion, list):
         if len(a) != len(b):
             return False
 
-        for i in xrange(len(self)):
+        for i in range(len(self)):
             e1, is_func1 = a[i]
             e2, is_func2 = b[i]
 
@@ -423,7 +419,7 @@ class Expansion(BaseExpansion, list):
     def __ne__(self, other):
         return not self.__eq__(other)
 
-class Variables(object):
+class Variables:
     """
     A mapping from variable names to variables. Variables have flavor, source, and value. The value is an 
     expansion object.
@@ -447,7 +443,7 @@ class Variables(object):
         self.parent = parent
 
     def readfromenvironment(self, env):
-        for k, v in env.iteritems():
+        for k, v in env.items():
             self.set(k, self.FLAVOR_RECURSIVE, self.SOURCE_ENVIRONMENT, v)
 
     def get(self, name, expand=True):
@@ -462,7 +458,7 @@ class Variables(object):
         flavor, source, valuestr, valueexp = self._map.get(name, (None, None, None, None))
         if flavor is not None:
             if expand and flavor != self.FLAVOR_SIMPLE and valueexp is None:
-                d = parser.Data.fromstring(valuestr, parserdata.Location("Expansion of variables '%s'" % (name,), 1, 0))
+                d = parser.Data.fromstring(valuestr, parserdata.Location("Expansion of variables '{}'".format(name), 1, 0))
                 valueexp, t, o = parser.parsemakesyntax(d, 0, (), parser.iterdata)
                 self._map[name] = flavor, source, valuestr, valueexp
 
@@ -495,7 +491,7 @@ class Variables(object):
             if flavor == self.FLAVOR_RECURSIVE:
                 val = valueexp
             else:
-                val = Expansion.fromstring(valuestr, "Expansion of variable '%s'" % (name,))
+                val = Expansion.fromstring(valuestr, "Expansion of variable '{}'".format(name))
 
             return flavor, source, val
 
@@ -512,7 +508,7 @@ class Variables(object):
         prevflavor, prevsource, prevvalue = self.get(name)
         if prevsource is not None and source > prevsource and not force:
             # TODO: give a location for this warning
-            _log.info("not setting variable '%s', set by higher-priority source to value '%s'" % (name, prevvalue))
+            _log.info("not setting variable '{}', set by higher-priority source to value '{}'".format(name, prevvalue))
             return
 
         self._map[name] = flavor, source, value, None
@@ -531,7 +527,7 @@ class Variables(object):
             return
 
         if prevflavor == self.FLAVOR_SIMPLE:
-            d = parser.Data.fromstring(value, parserdata.Location("Expansion of variables '%s'" % (name,), 1, 0))
+            d = parser.Data.fromstring(value, parserdata.Location("Expansion of variables '{}'".format(name), 1, 0))
             valueexp, t, o = parser.parsemakesyntax(d, 0, (), parser.iterdata)
 
             val = valueexp.resolvestr(makefile, variables, [name])
@@ -547,13 +543,13 @@ class Variables(object):
             self.set(k, flavor, source, value)
 
     def __iter__(self):
-        for k, (flavor, source, value, valueexp) in self._map.iteritems():
+        for k, (flavor, source, value, valueexp) in self._map.items():
             yield k, flavor, source, value
 
     def __contains__(self, item):
         return item in self._map
 
-class Pattern(object):
+class Pattern:
     """
     A pattern is a string, possibly with a % substitution character. From the GNU make manual:
 
@@ -561,7 +557,7 @@ class Pattern(object):
     would otherwise quote '%' charcters can be quoted with more backslashes. Backslashes that
     quote '%' characters or other backslashes are removed from the pattern before it is compared t
     file names or has a stem substituted into it. Backslashes that are not in danger of quoting '%'
-    characters go unmolested. For example, the pattern the\%weird\\%pattern\\ has `the%weird\' preceding
+    characters go unmolested. For example, the pattern the\\%weird\\%pattern\\ has `the%weird\' preceding
     the operative '%' character, and 'pattern\\' following it. The final two backslashes are left alone
     because they cannot affect any '%' character.
 
@@ -658,7 +654,7 @@ class Pattern(object):
         stem = self.match(word)
         if stem is None:
             if mustmatch:
-                raise DataError("target '%s' doesn't match pattern" % (word,))
+                raise DataError("target '{}' doesn't match pattern".format(word))
             return word
 
         if not self.ispattern():
@@ -668,7 +664,7 @@ class Pattern(object):
         return Pattern(replacement).resolve('', stem)
 
     def __repr__(self):
-        return "<Pattern with data %r>" % (self.data,)
+        return "<Pattern with data {!r}>".format(self.data)
 
     _backre = re.compile(r'[%\\]')
     def __str__(self):
@@ -677,7 +673,7 @@ class Pattern(object):
 
         return self._backre.sub(r'\\\1', self.data[0]) + '%' + self.data[1]
 
-class RemakeTargetSerially(object):
+class RemakeTargetSerially:
     __slots__ = ('target', 'makefile', 'indent', 'rlist')
 
     def __init__(self, target, makefile, indent, rlist):
@@ -722,7 +718,7 @@ class RemakeTargetSerially(object):
         else:
             self.rlist[0].resolvedeps(True, self.resolvecb)
 
-class RemakeTargetParallel(object):
+class RemakeTargetParallel:
     __slots__ = ('target', 'makefile', 'indent', 'rlist', 'rulesremaining', 'currunning')
 
     def __init__(self, target, makefile, indent, rlist):
@@ -793,7 +789,7 @@ class RemakeTargetParallel(object):
         self.currunning = False
         self.runnext()
 
-class RemakeRuleContext(object):
+class RemakeRuleContext:
     def __init__(self, target, makefile, rule, deps,
                  targetstack, avoidremakeloop):
         self.target = target
@@ -864,7 +860,7 @@ class RemakeRuleContext(object):
         assert error in (True, False)
 
         if error:
-            print "<%s>: Found error" % self.target.target
+            print("<%s>: Found error" % self.target.target)
             self.error = True
         if didanything:
             self.didanything = True
@@ -949,8 +945,8 @@ class RemakeRuleContext(object):
             self.target.didanything = True
             try:
                 self.commands = [c for c in self.rule.getcommands(self.target, self.makefile)]
-            except util.MakeError, e:
-                print e
+            except util.MakeError as e:
+                print(e)
                 sys.stdout.flush()
                 cb(error=True)
                 return
@@ -963,7 +959,7 @@ MAKESTATE_NONE = 0
 MAKESTATE_FINISHED = 1
 MAKESTATE_WORKING = 2
 
-class Target(object):
+class Target:
     """
     An actual (non-pattern) target.
 
@@ -1027,7 +1023,7 @@ class Target(object):
 
         candidates = [] # list of PatternRuleInstance
 
-        hasmatch = util.any((r.hasspecificmatch(file) for r in makefile.implicitrules))
+        hasmatch = util.any(r.hasspecificmatch(file) for r in makefile.implicitrules)
 
         for r in makefile.implicitrules:
             if r in rulestack:
@@ -1109,7 +1105,7 @@ class Target(object):
         assert makefile.parsingfinished
 
         if self.target in targetstack:
-            raise ResolutionError("Recursive dependency: %s -> %s" % (
+            raise ResolutionError("Recursive dependency: {} -> {}".format(
                     " -> ".join(targetstack), self.target))
 
         targetstack = targetstack + [self.target]
@@ -1136,9 +1132,9 @@ class Target(object):
         # depend on it are always out of date. This is like .FORCE but more
         # compatible with other makes.
         # Otherwise, we don't know how to make it.
-        if not len(self.rules) and self.mtime is None and not util.any((len(rule.prerequisites) > 0
-                                                                        for rule in self.rules)):
-            raise ResolutionError("No rule to make target '%s' needed by %r" % (self.target,
+        if not len(self.rules) and self.mtime is None and not util.any(len(rule.prerequisites) > 0
+                                                                        for rule in self.rules):
+            raise ResolutionError("No rule to make target '{}' needed by {!r}".format(self.target,
                                                                                 targetstack))
 
         if recursive:
@@ -1283,9 +1279,9 @@ class Target(object):
 
         try:
             self.resolvedeps(makefile, targetstack, [], False)
-        except util.MakeError, e:
+        except util.MakeError as e:
             if printerror:
-                print e
+                print(e)
             self.error = True
             self.notifydone(makefile)
             return
@@ -1334,8 +1330,8 @@ def filepart(p):
 
 def setautomatic(v, name, plist):
     v.set(name, Variables.FLAVOR_SIMPLE, Variables.SOURCE_AUTOMATIC, ' '.join(plist))
-    v.set(name + 'D', Variables.FLAVOR_SIMPLE, Variables.SOURCE_AUTOMATIC, ' '.join((dirpart(p) for p in plist)))
-    v.set(name + 'F', Variables.FLAVOR_SIMPLE, Variables.SOURCE_AUTOMATIC, ' '.join((filepart(p) for p in plist)))
+    v.set(name + 'D', Variables.FLAVOR_SIMPLE, Variables.SOURCE_AUTOMATIC, ' '.join(dirpart(p) for p in plist))
+    v.set(name + 'F', Variables.FLAVOR_SIMPLE, Variables.SOURCE_AUTOMATIC, ' '.join(filepart(p) for p in plist))
 
 def setautomaticvariables(v, makefile, target, prerequisites):
     prtargets = [makefile.gettarget(p) for p in prerequisites]
@@ -1387,7 +1383,7 @@ def findmodifiers(command):
     modset = set(command[:-len(realcommand)])
     return realcommand, '@' in modset, '+' in modset, '-' in modset, '%' in modset
 
-class _CommandWrapper(object):
+class _CommandWrapper:
     def __init__(self, cline, ignoreErrors, loc, context, **kwargs):
         self.ignoreErrors = ignoreErrors
         self.loc = loc
@@ -1397,7 +1393,7 @@ class _CommandWrapper(object):
 
     def _cb(self, res):
         if res != 0 and not self.ignoreErrors:
-            print "%s: command '%s' failed, return code %i" % (self.loc, self.cline, res)
+            print("%s: command '%s' failed, return code %i" % (self.loc, self.cline, res))
             self.usercb(error=True)
         else:
             self.usercb(error=False)
@@ -1412,7 +1408,7 @@ class _NativeWrapper(_CommandWrapper):
         _CommandWrapper.__init__(self, cline, ignoreErrors, loc, context,
                                  **kwargs)
         if pycommandpath:
-            self.pycommandpath = re.split('[%s\s]+' % os.pathsep,
+            self.pycommandpath = re.split(r'[%s\s]+' % os.pathsep,
                                           pycommandpath)
         else:
             self.pycommandpath = None
@@ -1421,7 +1417,7 @@ class _NativeWrapper(_CommandWrapper):
         # get the module and method to call
         parts, badchar = process.clinetoargv(self.cline, self.kwargs['cwd'])
         if parts is None:
-            raise DataError("native command '%s': shell metacharacter '%s' in command line" % (self.cline, badchar), self.loc)
+            raise DataError("native command '{}': shell metacharacter '{}' in command line".format(self.cline, badchar), self.loc)
         if len(parts) < 2:
             raise DataError("native command '%s': no method name specified" % self.cline, self.loc)
         module = parts[0]
@@ -1447,7 +1443,7 @@ def getcommandsforrule(rule, target, makefile, prerequisites, stem):
             if (isHidden or makefile.silent) and not makefile.justprint:
                 echo = None
             else:
-                echo = "%s$ %s" % (c.loc, cline)
+                echo = "{}$ {}".format(c.loc, cline)
             if not isNative:
                 yield _CommandWrapper(cline, ignoreErrors=ignoreErrors, env=env, cwd=makefile.workdir, loc=c.loc, context=makefile.context,
                                       echo=echo, justprint=makefile.justprint)
@@ -1461,7 +1457,7 @@ def getcommandsforrule(rule, target, makefile, prerequisites, stem):
                                      echo=echo, justprint=makefile.justprint,
                                      pycommandpath=e)
 
-class Rule(object):
+class Rule:
     """
     A rule contains a list of prerequisites and a list of commands. It may also
     contain rule-specific variables. This rule may be associated with multiple targets.
@@ -1496,7 +1492,7 @@ class Rule(object):
         return getcommandsforrule(self, target, makefile, prereqs, stem=None)
         # TODO: $* in non-pattern rules?
 
-class PatternRuleInstance(object):
+class PatternRuleInstance:
     weakdeps = False
 
     """
@@ -1520,12 +1516,12 @@ class PatternRuleInstance(object):
         return getcommandsforrule(self, target, makefile, self.prerequisites, stem=self.dir + self.stem)
 
     def __str__(self):
-        return "Pattern rule at %s with stem '%s', matchany: %s doublecolon: %s" % (self.loc,
+        return "Pattern rule at {} with stem '{}', matchany: {} doublecolon: {}".format(self.loc,
                                                                                     self.dir + self.stem,
                                                                                     self.ismatchany,
                                                                                     self.doublecolon)
 
-class PatternRule(object):
+class PatternRule:
     """
     An implicit rule or static pattern rule containing target patterns, prerequisite patterns,
     and a list of commands.
@@ -1543,7 +1539,7 @@ class PatternRule(object):
         self.commands.append(c)
 
     def ismatchany(self):
-        return util.any((t.ismatchany() for t in self.targetpatterns))
+        return util.any(t.ismatchany() for t in self.targetpatterns)
 
     def hasspecificmatch(self, file):
         for p in self.targetpatterns:
@@ -1577,7 +1573,7 @@ class PatternRule(object):
     def prerequisitesforstem(self, dir, stem):
         return [p.resolve(dir, stem) for p in self.prerequisites]
 
-class _RemakeContext(object):
+class _RemakeContext:
     def __init__(self, makefile, cb):
         self.makefile = makefile
         self.included = [(makefile.gettarget(f), required)
@@ -1591,7 +1587,7 @@ class _RemakeContext(object):
         assert error in (True, False)
 
         if error and self.required:
-            print "Error remaking makefiles (ignored)"
+            print("Error remaking makefiles (ignored)")
 
         if len(self.toremake):
             target, self.required = self.toremake.pop(0)
@@ -1608,7 +1604,7 @@ class _RemakeContext(object):
 
             self.cb(remade=False)
 
-class Makefile(object):
+class Makefile:
     """
     The top-level data structure for makefile execution. It holds Targets, implicit rules, and other
     state data.
@@ -1678,7 +1674,7 @@ class Makefile(object):
         self.variables.set('MAKECMDGOALS', Variables.FLAVOR_SIMPLE,
                            Variables.SOURCE_AUTOMATIC, ' '.join(targets))
 
-        for vname, val in implicit.variables.iteritems():
+        for vname, val in implicit.variables.items():
             self.variables.set(vname,
                                Variables.FLAVOR_SIMPLE,
                                Variables.SOURCE_IMPLICIT, val)
@@ -1750,11 +1746,10 @@ class Makefile(object):
         if value is None:
             self._vpath = []
         else:
-            self._vpath = filter(lambda e: e != '',
-                                 re.split('[%s\s]+' % os.pathsep,
-                                          value.resolvestr(self, self.variables, ['VPATH'])))
+            self._vpath = [e for e in re.split(r'[%s\s]+' % os.pathsep,
+                                          value.resolvestr(self, self.variables, ['VPATH'])) if e != '']
 
-        targets = list(self._targets.itervalues())
+        targets = list(self._targets.values())
         for t in targets:
             t.explicit = True
             for r in t.rules:
@@ -1825,7 +1820,7 @@ class Makefile(object):
 
     def getsubenvironment(self, variables):
         env = dict(self.env)
-        for vname, v in self.exportedvars.iteritems():
+        for vname, v in self.exportedvars.items():
             if v:
                 flavor, source, val = variables.get(vname)
                 if val is None:
diff --git a/build/pymake/pymake/functions.py b/build/pymake/pymake/functions.py
index e53fb54726..a8b738b638 100644
--- a/build/pymake/pymake/functions.py
+++ b/build/pymake/pymake/functions.py
@@ -19,12 +19,11 @@ def emit_expansions(descend, *expansions):
 
         for e, is_func in expansion:
             if is_func:
-                for exp in e.expansions(True):
-                    yield exp
+                yield from e.expansions(True)
             else:
                 yield e
 
-class Function(object):
+class Function:
     """
     An object that represents a function call. This class is always subclassed
     with the following methods and attributes:
@@ -51,7 +50,7 @@ class Function(object):
         argc = len(self._arguments)
 
         if argc < self.minargs:
-            raise data.DataError("Not enough arguments to function %s, requires %s" % (self.name, self.minargs), self.loc)
+            raise data.DataError("Not enough arguments to function {}, requires {}".format(self.name, self.minargs), self.loc)
 
         assert self.maxargs == 0 or argc <= self.maxargs, "Parser screwed up, gave us too many args"
 
@@ -84,9 +83,9 @@ class Function(object):
             args.append(arg)
 
         if curly:
-            return '${%s %s}' % (self.name, ','.join(args))
+            return '${{{} {}}}'.format(self.name, ','.join(args))
 
-        return '$(%s %s)' % (self.name, ','.join(args))
+        return '$({} {})'.format(self.name, ','.join(args))
 
     def expansions(self, descend=False):
         """Obtain all expansions contained within this function.
@@ -117,7 +116,7 @@ class Function(object):
         return len(self._arguments)
 
     def __repr__(self):
-        return "%s<%s>(%r)" % (
+        return "{}<{}>({!r})".format(
             self.__class__.__name__, self.loc,
             ','.join([repr(a) for a in self._arguments]),
             )
@@ -160,7 +159,7 @@ class Function(object):
         return not self.__eq__(other)
 
 class VariableRef(Function):
-    AUTOMATIC_VARIABLES = set(['@', '%', '<', '?', '^', '+', '|', '*'])
+    AUTOMATIC_VARIABLES = {'@', '%', '<', '?', '^', '+', '|', '*'}
 
     __slots__ = ('vname', 'loc')
 
@@ -175,11 +174,11 @@ class VariableRef(Function):
     def resolve(self, makefile, variables, fd, setting):
         vname = self.vname.resolvestr(makefile, variables, setting)
         if vname in setting:
-            raise data.DataError("Setting variable '%s' recursively references itself." % (vname,), self.loc)
+            raise data.DataError("Setting variable '{}' recursively references itself.".format(vname), self.loc)
 
         flavor, source, value = variables.get(vname)
         if value is None:
-            log.debug("%s: variable '%s' was not set" % (self.loc, vname))
+            log.debug("{}: variable '{}' was not set".format(self.loc, vname))
             return
 
         value.resolve(makefile, variables, fd, setting + [vname])
@@ -197,7 +196,7 @@ class VariableRef(Function):
         return emit_expansions(descend, self.vname)
 
     def __repr__(self):
-        return "VariableRef<%s>(%r)" % (self.loc, self.vname)
+        return "VariableRef<{}>({!r})".format(self.loc, self.vname)
 
     def __eq__(self, other):
         if not isinstance(other, VariableRef):
@@ -222,14 +221,14 @@ class SubstitutionRef(Function):
     def resolve(self, makefile, variables, fd, setting):
         vname = self.vname.resolvestr(makefile, variables, setting)
         if vname in setting:
-            raise data.DataError("Setting variable '%s' recursively references itself." % (vname,), self.loc)
+            raise data.DataError("Setting variable '{}' recursively references itself.".format(vname), self.loc)
 
         substfrom = self.substfrom.resolvestr(makefile, variables, setting)
         substto = self.substto.resolvestr(makefile, variables, setting)
 
         flavor, source, value = variables.get(vname)
         if value is None:
-            log.debug("%s: variable '%s' was not set" % (self.loc, vname))
+            log.debug("{}: variable '{}' was not set".format(self.loc, vname))
             return
 
         f = data.Pattern(substfrom)
@@ -241,7 +240,7 @@ class SubstitutionRef(Function):
                            for word in value.resolvesplit(makefile, variables, setting + [vname])]))
 
     def to_source(self):
-        return '$(%s:%s=%s)' % (
+        return '$({}:{}={})'.format(
             self.vname.to_source(),
             self.substfrom.to_source(),
             self.substto.to_source())
@@ -251,8 +250,8 @@ class SubstitutionRef(Function):
                 self.substto)
 
     def __repr__(self):
-        return "SubstitutionRef<%s>(%r:%r=%r)" % (
-            self.loc, self.vname, self.substfrom, self.substto,)
+        return "SubstitutionRef<{}>({!r}:{!r}={!r})".format(
+            self.loc, self.vname, self.substfrom, self.substto)
 
     def __eq__(self, other):
         if not isinstance(other, SubstitutionRef):
@@ -325,7 +324,7 @@ class FilterFunction(Function):
                  for p in self._arguments[0].resolvesplit(makefile, variables, setting)]
 
         fd.write(' '.join([w for w in self._arguments[1].resolvesplit(makefile, variables, setting)
-                           if util.any((p.match(w) for p in plist))]))
+                           if util.any(p.match(w) for p in plist)]))
 
 class FilteroutFunction(Function):
     name = 'filter-out'
@@ -339,7 +338,7 @@ class FilteroutFunction(Function):
                  for p in self._arguments[0].resolvesplit(makefile, variables, setting)]
 
         fd.write(' '.join([w for w in self._arguments[1].resolvesplit(makefile, variables, setting)
-                           if not util.any((p.match(w) for p in plist))]))
+                           if not util.any(p.match(w) for p in plist)]))
 
 class SortFunction(Function):
     name = 'sort'
@@ -666,7 +665,7 @@ class CallFunction(Function):
     def resolve(self, makefile, variables, fd, setting):
         vname = self._arguments[0].resolvestr(makefile, variables, setting)
         if vname in setting:
-            raise data.DataError("Recursively setting variable '%s'" % (vname,))
+            raise data.DataError("Recursively setting variable '{}'".format(vname))
 
         v = data.Variables(parent=variables)
         v.set('0', data.Variables.FLAVOR_SIMPLE, data.Variables.SOURCE_AUTOMATIC, vname)
@@ -680,7 +679,7 @@ class CallFunction(Function):
             return
 
         if flavor == data.Variables.FLAVOR_SIMPLE:
-            log.warning("%s: calling variable '%s' which is simply-expanded" % (self.loc, vname))
+            log.warning("{}: calling variable '{}' which is simply-expanded".format(self.loc, vname))
 
         # but we'll do it anyway
         e.resolve(makefile, v, fd, setting + [vname])
@@ -781,12 +780,12 @@ class ShellFunction(Function):
         if makefile.env is not None and 'PATH' in makefile.env:
             os.environ['PATH'] = makefile.env['PATH']
 
-        log.debug("%s: running command '%s'" % (self.loc, ' '.join(cline)))
+        log.debug("{}: running command '{}'".format(self.loc, ' '.join(cline)))
         try:
             p = subprocess.Popen(cline, executable=executable, env=makefile.env, shell=False,
                                  stdout=subprocess.PIPE, cwd=makefile.workdir)
-        except OSError, e:
-            print >>sys.stderr, "Error executing command %s" % cline[0], e
+        except OSError as e:
+            print("Error executing command %s" % cline[0], e, file=sys.stderr)
             return
         finally:
             os.environ['PATH'] = oldpath
@@ -830,7 +829,7 @@ class InfoFunction(Function):
 
     def resolve(self, makefile, variables, fd, setting):
         v = self._arguments[0].resolvestr(makefile, variables, setting)
-        print v
+        print(v)
 
 functionmap = {
     'subst': SubstFunction,
diff --git a/build/pymake/pymake/globrelative.py b/build/pymake/pymake/globrelative.py
index 37ca28e068..3dbce4eb8a 100644
--- a/build/pymake/pymake/globrelative.py
+++ b/build/pymake/pymake/globrelative.py
@@ -7,7 +7,7 @@ Filename globbing like the python glob module with minor differences:
 """
 
 import os, re, fnmatch
-import util
+from . import util
 
 _globcheck = re.compile('[[*?]')
 
@@ -35,7 +35,7 @@ def glob(fsdir, path):
         if not os.path.isdir(fspath):
             continue
 
-        r.extend((util.normaljoin(dir, found) for found in globpattern(fspath, leaf)))
+        r.extend(util.normaljoin(dir, found) for found in globpattern(fspath, leaf))
 
     return r
 
@@ -62,7 +62,7 @@ def globpattern(dir, pattern):
                   if not leaf.startswith('.')]
 
     leaves = fnmatch.filter(leaves, pattern)
-    leaves = filter(lambda l: os.path.exists(util.normaljoin(dir, l)), leaves)
+    leaves = [l for l in leaves if os.path.exists(util.normaljoin(dir, l))]
 
     leaves.sort()
     return leaves
diff --git a/build/pymake/pymake/parser.py b/build/pymake/pymake/parser.py
index 4bff533688..56e3be6ce7 100644
--- a/build/pymake/pymake/parser.py
+++ b/build/pymake/pymake/parser.py
@@ -34,15 +34,15 @@ coming.
 """
 
 import logging, re, os, sys
-import data, functions, util, parserdata
+from . import data, functions, util, parserdata
 
 _log = logging.getLogger('pymake.parser')
 
 class SyntaxError(util.MakeError):
     pass
 
-_skipws = re.compile('\S')
-class Data(object):
+_skipws = re.compile(r'\S')
+class Data:
     """
     A single virtual "line", which can be multiple source lines joined with
     continuations.
@@ -108,7 +108,7 @@ _alltokens = re.compile(r'''\\*\# | # hash mark preceeded by any number of backs
                             :: |
                             (?:\$(?:$|[\(\{](?:%s)\s+|.)) | # dollar sign followed by EOF, a function keyword with whitespace, or any character
                             :(?![\\/]) | # colon followed by anything except a slash (Windows path detection)
-                            [=#{}();,|'"]''' % '|'.join(functions.functionmap.iterkeys()), re.VERBOSE)
+                            [=#{}();,|'"]''' % '|'.join(functions.functionmap.keys()), re.VERBOSE)
 
 def iterdata(d, offset, tokenlist, it):
     """
@@ -233,7 +233,7 @@ def itercommandchars(d, offset, tokenlist, it):
 
     yield s[offset:d.lend].replace('\n\t', '\n'), None, None, None
 
-_redefines = re.compile('\s*define|\s*endef')
+_redefines = re.compile(r'\s*define|\s*endef')
 def iterdefinelines(it, startloc):
     """
     Process the insides of a define. Most characters are included literally. Escaped newlines are treated
@@ -336,7 +336,7 @@ _conditionkeywords = {
     'ifndef': ifndef
     }
 
-_conditiontokens = tuple(_conditionkeywords.iterkeys())
+_conditiontokens = tuple(_conditionkeywords.keys())
 _conditionre = re.compile(r'(%s)(?:$|\s+)' % '|'.join(_conditiontokens))
 
 _directivestokenlist = _conditiontokens + \
@@ -347,7 +347,7 @@ _directivesre = re.compile(r'(%s)(?:$|\s+)' % '|'.join(_directivestokenlist))
 _varsettokens = (':=', '+=', '?=', '=')
 
 def _parsefile(pathname):
-    fd = open(pathname, "rU")
+    fd = open(pathname)
     stmts = parsestring(fd.read(), pathname)
     stmts.mtime = os.fstat(fd.fileno()).st_mtime
     fd.close()
@@ -375,7 +375,7 @@ def parsefile(pathname):
 # colon followed by anything except a slash (Windows path detection)
 _depfilesplitter = re.compile(r':(?![\\/])')
 # simple variable references
-_vars = re.compile('\$\((\w+)\)')
+_vars = re.compile(r'\$\((\w+)\)')
 
 def parsedepfile(pathname):
     """
@@ -641,7 +641,7 @@ _PARSESTATE_SUBSTFROM = 3   # expanding a variable expansion substitution "from"
 _PARSESTATE_SUBSTTO = 4     # expanding a variable expansion substitution "to" value
 _PARSESTATE_PARENMATCH = 5  # inside nested parentheses/braces that must be matched
 
-class ParseStackFrame(object):
+class ParseStackFrame:
     __slots__ = ('parsestate', 'parent', 'expansion', 'tokenlist', 'openbrace', 'closebrace', 'function', 'loc', 'varname', 'substfrom')
 
     def __init__(self, parsestate, parent, expansion, tokenlist, openbrace, closebrace, function=None, loc=None):
@@ -691,7 +691,7 @@ def parsemakesyntax(d, offset, stopon, iterfunc):
     while True: # this is not a for loop because `di` changes during the function
         assert stacktop is not None
         try:
-            s, token, tokenoffset, offset = di.next()
+            s, token, tokenoffset, offset = next(di)
         except StopIteration:
             break
 
diff --git a/build/pymake/pymake/parserdata.py b/build/pymake/pymake/parserdata.py
index 7b2e5443d5..e1368c237e 100644
--- a/build/pymake/pymake/parserdata.py
+++ b/build/pymake/pymake/parserdata.py
@@ -1,12 +1,12 @@
 import logging, re, os
-import data, parser, functions, util
+from . import data, parser, functions, util
 from cStringIO import StringIO
 from pymake.globrelative import hasglob, glob
 
 _log = logging.getLogger('pymake.data')
 _tabwidth = 4
 
-class Location(object):
+class Location:
     """
     A location within a makefile.
 
@@ -54,7 +54,7 @@ class Location(object):
         return Location(self.path, line, column)
 
     def __str__(self):
-        return "%s:%s:%s" % (self.path, self.line, self.column)
+        return "{}:{}:{}".format(self.path, self.line, self.column)
 
 def _expandwildcards(makefile, tlist):
     for t in tlist:
@@ -62,8 +62,7 @@ def _expandwildcards(makefile, tlist):
             yield t
         else:
             l = glob(makefile.workdir, t)
-            for r in l:
-                yield r
+            yield from l
 
 _flagescape = re.compile(r'([\s\\])')
 
@@ -76,7 +75,7 @@ def parsecommandlineargs(args):
     overrides = []
     stmts = StatementList()
     r = []
-    for i in xrange(0, len(args)):
+    for i in range(0, len(args)):
         a = args[i]
 
         vname, t, val = util.strpartition(a, ':=')
@@ -97,7 +96,7 @@ def parsecommandlineargs(args):
 
     return stmts, r, ' '.join(overrides)
 
-class Statement(object):
+class Statement:
     """
     Represents parsed make file syntax.
 
@@ -123,7 +122,7 @@ class Statement(object):
     def __ne__(self, other):
         return self.__eq__(other)
 
-class DummyRule(object):
+class DummyRule:
     __slots__ = ()
 
     def addcommand(self, r):
@@ -188,14 +187,14 @@ class Rule(Statement):
             context.currule = DummyRule()
             return
 
-        ispatterns = set((t.ispattern() for t in targets))
+        ispatterns = {t.ispattern() for t in targets}
         if len(ispatterns) == 2:
             raise data.DataError("Mixed implicit and normal rule", self.targetexp.loc)
         ispattern, = ispatterns
 
         deps = list(_expandwildcards(makefile, data.stripdotslashes(self.depexp.resolvesplit(makefile, makefile.variables))))
         if ispattern:
-            rule = data.PatternRule(targets, map(data.Pattern, deps), self.doublecolon, loc=self.targetexp.loc)
+            rule = data.PatternRule(targets, list(map(data.Pattern, deps)), self.doublecolon, loc=self.targetexp.loc)
             makefile.appendimplicitrule(rule)
         else:
             rule = data.Rule(deps, self.doublecolon, loc=self.targetexp.loc, weakdeps=False)
@@ -207,7 +206,7 @@ class Rule(Statement):
         context.currule = rule
 
     def dump(self, fd, indent):
-        print >>fd, "%sRule %s: %s" % (indent, self.targetexp, self.depexp)
+        print("{}Rule {}: {}".format(indent, self.targetexp, self.depexp, file=fd))
 
     def to_source(self):
         sep = ':'
@@ -219,7 +218,7 @@ class Rule(Statement):
         if len(deps) > 0 and not deps[0].isspace():
             sep += ' '
 
-        return '\n%s%s%s' % (
+        return '\n{}{}{}'.format(
             self.targetexp.to_source(escape_variables=True),
             sep,
             deps)
@@ -275,17 +274,17 @@ class StaticPatternRule(Statement):
 
         for t in targets:
             if data.Pattern(t).ispattern():
-                raise data.DataError("Target '%s' of a static pattern rule must not be a pattern" % (t,), self.targetexp.loc)
+                raise data.DataError("Target '{}' of a static pattern rule must not be a pattern".format(t), self.targetexp.loc)
             stem = pattern.match(t)
             if stem is None:
-                raise data.DataError("Target '%s' does not match the static pattern '%s'" % (t, pattern), self.targetexp.loc)
+                raise data.DataError("Target '{}' does not match the static pattern '{}'".format(t, pattern), self.targetexp.loc)
             makefile.gettarget(t).addrule(data.PatternRuleInstance(rule, '', stem, pattern.ismatchany()))
 
         makefile.foundtarget(targets[0])
         context.currule = rule
 
     def dump(self, fd, indent):
-        print >>fd, "%sStaticPatternRule %s: %s: %s" % (indent, self.targetexp, self.patternexp, self.depexp)
+        print("{}StaticPatternRule {}: {}: {}".format(indent, self.targetexp, self.patternexp, self.depexp, file=fd))
 
     def to_source(self):
         sep = ':'
@@ -299,7 +298,7 @@ class StaticPatternRule(Statement):
         if len(pattern) > 0 and pattern[0] not in (' ', '\t'):
             sep += ' '
 
-        return '\n%s%s%s:%s' % (
+        return '\n{}{}{}:{}'.format(
             self.targetexp.to_source(escape_variables=True),
             sep,
             pattern,
@@ -339,7 +338,7 @@ class Command(Statement):
         context.currule.addcommand(self.exp)
 
     def dump(self, fd, indent):
-        print >>fd, "%sCommand %s" % (indent, self.exp,)
+        print("{}Command {}".format(indent, self.exp, file=fd))
 
     def to_source(self):
         # Commands have some interesting quirks when it comes to source
@@ -438,7 +437,7 @@ class SetVariable(Statement):
             v.set(vname, flavor, self.source, value)
 
     def dump(self, fd, indent):
-        print >>fd, "%sSetVariable<%s> %s %s\n%s %r" % (indent, self.valueloc, self.vnameexp, self.token, indent, self.value)
+        print("{}SetVariable<{}> {} {}\n{} {!r}".format(indent, self.valueloc, self.vnameexp, self.token, indent, self.value, file=fd))
 
     def __eq__(self, other):
         if not isinstance(other, SetVariable):
@@ -452,7 +451,7 @@ class SetVariable(Statement):
 
     def to_source(self):
         chars = []
-        for i in xrange(0, len(self.value)):
+        for i in range(0, len(self.value)):
             c = self.value[i]
 
             # Literal # is escaped in variable assignment otherwise it would be
@@ -477,7 +476,7 @@ class SetVariable(Statement):
 
         # We handle the target-specific syntax first.
         if self.targetexp is not None:
-            return '%s: %s %s %s' % (
+            return '{}: {} {} {}'.format(
                 self.targetexp.to_source(),
                 self.vnameexp.to_source(),
                 self.token,
@@ -489,18 +488,18 @@ class SetVariable(Statement):
         # the variable must have come from a define.
         if value.count('\n') > 0 or (len(value) and value[0].isspace()):
             # The parser holds the token in vnameexp for whatever reason.
-            return '%sdefine %s\n%s\nendef' % (
+            return '{}define {}\n{}\nendef'.format(
                 prefix,
                 self.vnameexp.to_source(),
                 value)
 
-        return '%s%s %s %s' % (
+        return '{}{} {} {}'.format(
                 prefix,
                 self.vnameexp.to_source(),
                 self.token,
                 value)
 
-class Condition(object):
+class Condition:
     """
     An abstract "condition", either ifeq or ifdef, perhaps negated.
 
@@ -543,7 +542,7 @@ class EqCondition(Condition):
         return (r1 == r2) == self.expected
 
     def __str__(self):
-        return "ifeq (expected=%s) %s %s" % (self.expected, self.exp1, self.exp2)
+        return "ifeq (expected={}) {} {}".format(self.expected, self.exp1, self.exp2)
 
     def __eq__(self, other):
         if not isinstance(other, EqCondition):
@@ -580,7 +579,7 @@ class IfdefCondition(Condition):
         return (len(value) > 0) == self.expected
 
     def __str__(self):
-        return "ifdef (expected=%s) %s" % (self.expected, self.exp)
+        return "ifdef (expected={}) {}".format(self.expected, self.exp)
 
     def __eq__(self, other):
         if not isinstance(other, IfdefCondition):
@@ -651,14 +650,14 @@ class ConditionBlock(Statement):
             i += 1
 
     def dump(self, fd, indent):
-        print >>fd, "%sConditionBlock" % (indent,)
+        print("{}ConditionBlock".format(indent, file=fd))
 
         indent2 = indent + '  '
         for c, statements in self._groups:
-            print >>fd, "%s Condition %s" % (indent, c)
+            print("{} Condition {}".format(indent, c, file=fd))
             statements.dump(fd, indent2)
-            print >>fd, "%s ~Condition" % (indent,)
-        print >>fd, "%s~ConditionBlock" % (indent,)
+            print("{} ~Condition".format(indent, file=fd))
+        print("{}~ConditionBlock".format(indent, file=fd))
 
     def to_source(self):
         lines = []
@@ -681,7 +680,7 @@ class ConditionBlock(Statement):
         if len(self) != len(other):
             return False
 
-        for i in xrange(0, len(self)):
+        for i in range(0, len(self)):
             our_condition, our_statements = self[i]
             other_condition, other_statements = other[i]
 
@@ -709,9 +708,9 @@ class ConditionBlock(Statement):
             s = statement.exp.s
 
             if statement.expected:
-                return '%sifdef %s' % (prefix, s)
+                return '{}ifdef {}'.format(prefix, s)
 
-            return '%sifndef %s' % (prefix, s)
+            return '{}ifndef {}'.format(prefix, s)
 
         if isinstance(statement, EqCondition):
             args = [
@@ -750,9 +749,9 @@ class ConditionBlock(Statement):
                 body = '(%s)' % ','.join(args)
 
             if statement.expected:
-                return '%sifeq %s' % (prefix, body)
+                return '{}ifeq {}'.format(prefix, body)
 
-            return '%sifneq %s' % (prefix, body)
+            return '{}ifneq {}'.format(prefix, body)
 
         if isinstance(statement, ElseCondition):
             return 'else'
@@ -793,7 +792,7 @@ class Include(Statement):
             makefile.include(f, self.required, loc=self.exp.loc, weak=self.weak)
 
     def dump(self, fd, indent):
-        print >>fd, "%sInclude %s" % (indent, self.exp)
+        print("{}Include {}".format(indent, self.exp, file=fd))
 
     def to_source(self):
         prefix = ''
@@ -801,7 +800,7 @@ class Include(Statement):
         if not self.required:
             prefix = '-'
 
-        return '%sinclude %s' % (prefix, self.exp.to_source())
+        return '{}include {}'.format(prefix, self.exp.to_source())
 
     def __eq__(self, other):
         if not isinstance(other, Include):
@@ -834,13 +833,13 @@ class VPathDirective(Statement):
             else:
                 dirs = []
                 for mpath in mpaths:
-                    dirs.extend((dir for dir in mpath.split(os.pathsep)
-                                 if dir != ''))
+                    dirs.extend(dir for dir in mpath.split(os.pathsep)
+                                 if dir != '')
                 if len(dirs):
                     makefile.addvpath(pattern, dirs)
 
     def dump(self, fd, indent):
-        print >>fd, "%sVPath %s" % (indent, self.exp)
+        print("{}VPath {}".format(indent, self.exp, file=fd))
 
     def to_source(self):
         return 'vpath %s' % self.exp.to_source()
@@ -885,7 +884,7 @@ class ExportDirective(Statement):
             makefile.exportedvars[v] = True
 
     def dump(self, fd, indent):
-        print >>fd, "%sExport (single=%s) %s" % (indent, self.single, self.exp)
+        print("{}Export (single={}, file=fd) {}".format(indent, self.single, self.exp))
 
     def to_source(self):
         return ('export %s' % self.exp.to_source()).rstrip()
@@ -915,7 +914,7 @@ class UnexportDirective(Statement):
             makefile.exportedvars[v] = False
 
     def dump(self, fd, indent):
-        print >>fd, "%sUnexport %s" % (indent, self.exp)
+        print("{}Unexport {}".format(indent, self.exp, file=fd))
 
     def to_source(self):
         return 'unexport %s' % self.exp.to_source()
@@ -947,7 +946,7 @@ class EmptyDirective(Statement):
             raise data.DataError("Line expands to non-empty value", self.exp.loc)
 
     def dump(self, fd, indent):
-        print >>fd, "%sEmptyDirective: %s" % (indent, self.exp)
+        print("{}EmptyDirective: {}".format(indent, self.exp, file=fd))
 
     def to_source(self):
         return self.exp.to_source()
@@ -958,7 +957,7 @@ class EmptyDirective(Statement):
 
         return self.exp == other.exp
 
-class _EvalContext(object):
+class _EvalContext:
     __slots__ = ('currule', 'weak')
 
     def __init__(self, weak):
@@ -1003,4 +1002,4 @@ def iterstatements(stmts):
         yield s
         if isinstance(s, ConditionBlock):
             for c, sl in s:
-                for s2 in iterstatments(sl): yield s2
+                yield from iterstatments(sl)
diff --git a/build/pymake/pymake/process.py b/build/pymake/pymake/process.py
index 01cadf5a99..f78d1f35e4 100644
--- a/build/pymake/pymake/process.py
+++ b/build/pymake/pymake/process.py
@@ -45,7 +45,7 @@ _unquoted_tokens = tokens2re({
 _doubly_quoted_tokens = tokens2re({
   'quote': '"',
   'backslashedquote': r'\\"',
-  'special': '\$',
+  'special': r'\$',
   'backslashed': r'\\[^\\"]',
 })
 
@@ -129,7 +129,7 @@ class ClineSplitter(list):
             elif 'special' in match:
                 # Unquoted, non-escaped special characters need to be sent to a
                 # shell.
-                raise MetaCharacterException, match['special']
+                raise MetaCharacterException(match['special'])
             elif 'whitespace' in match:
                 # Whitespaces terminate current argument.
                 self._next()
@@ -145,7 +145,7 @@ class ClineSplitter(list):
                 self.glob = True
                 self._push(m.group(0))
             else:
-                raise Exception, "Shouldn't reach here"
+                raise Exception("Shouldn't reach here")
         if self.arg:
             self._next()
 
@@ -153,17 +153,17 @@ class ClineSplitter(list):
         # Single quoted strings are preserved, except for the final quote
         index = self.cline.find("'")
         if index == -1:
-            raise Exception, 'Unterminated quoted string in command'
+            raise Exception('Unterminated quoted string in command')
         self._push(self.cline[:index])
         self.cline = self.cline[index+1:]
 
     def _parse_doubly_quoted(self):
         if not self.cline:
-            raise Exception, 'Unterminated quoted string in command'
+            raise Exception('Unterminated quoted string in command')
         while self.cline:
             m = _doubly_quoted_tokens.search(self.cline)
             if not m:
-                raise Exception, 'Unterminated quoted string in command'
+                raise Exception('Unterminated quoted string in command')
             self._push(self.cline[:m.start()])
             self.cline = self.cline[m.end():]
             match = dict([(name, value) for name, value in m.groupdict().items() if value])
@@ -175,7 +175,7 @@ class ClineSplitter(list):
                 # Unquoted, non-escaped special characters in a doubly quoted
                 # string still have a special meaning and need to be sent to a
                 # shell.
-                raise MetaCharacterException, match['special']
+                raise MetaCharacterException(match['special'])
             elif 'escape' in match:
                 # Escaped backslashes turn into a single backslash
                 self._push('\\')
@@ -194,7 +194,7 @@ def clinetoargv(cline, cwd):
     str = _escapednewlines.sub('', cline)
     try:
         args = ClineSplitter(str, cwd)
-    except MetaCharacterException, e:
+    except MetaCharacterException as e:
         return None, e.char
 
     if len(args) and args[0].find('=') != -1:
@@ -331,8 +331,8 @@ class PopenJob(Job):
                 os.environ['PATH'] = self.env['PATH']
             p = subprocess.Popen(self.argv, executable=self.executable, shell=self.shell, env=self.env, cwd=self.cwd)
             return p.wait()
-        except OSError, e:
-            print >>sys.stderr, e
+        except OSError as e:
+            print(e, file=sys.stderr)
             return -127
         finally:
             os.environ['PATH'] = oldpath
@@ -383,30 +383,30 @@ class PythonJob(Job):
                 try:
                     __import__(self.module)
                 except Exception as e:
-                    print >>sys.stderr, 'Error importing %s: %s' % (
+                    print('Error importing %s: %s' % (, file=sys.stderr)
                         self.module, e)
                     return -127
 
             m = sys.modules[self.module]
             if self.method not in m.__dict__:
-                print >>sys.stderr, "No method named '%s' in module %s" % (self.method, self.module)
+                print("No method named '%s' in module %s" % (self.method, self.module), file=sys.stderr)
                 return -127
             rv = m.__dict__[self.method](self.argv)
             if rv != 0 and rv is not None:
-                print >>sys.stderr, (
+                print((, file=sys.stderr)
                     "Native command '%s %s' returned value '%s'" %
                     (self.module, self.method, rv))
                 return (rv if isinstance(rv, int) else 1)
 
-        except PythonException, e:
-            print >>sys.stderr, e
+        except PythonException as e:
+            print(e, file=sys.stderr)
             return e.exitcode
         except:
             e = sys.exc_info()[1]
             if isinstance(e, SystemExit) and (e.code == 0 or e.code is None):
                 pass # sys.exit(0) is not a failure
             else:
-                print >>sys.stderr, e
+                print(e, file=sys.stderr)
                 traceback.print_exc()
                 return -127
         finally:
@@ -461,7 +461,7 @@ class ParallelContext(object):
 
     def _docall_generic(self, pool, job, cb, echo, justprint):
         if echo is not None:
-            print echo
+            print(echo)
         processcb = job.get_callback(ParallelContext._condition)
         if justprint:
             processcb(0)
@@ -525,7 +525,7 @@ class ParallelContext(object):
             for c in clist:
                 c.run()
 
-            dowait = util.any((len(c.running) for c in ParallelContext._allcontexts))
+            dowait = util.any(len(c.running) for c in ParallelContext._allcontexts)
             if dowait:
                 # Wait on local jobs first for perf
                 for job, cb in ParallelContext._waitany(ParallelContext._condition):
diff --git a/build/pymake/pymake/util.py b/build/pymake/pymake/util.py
index c63f930cc2..d3f193e54a 100644
--- a/build/pymake/pymake/util.py
+++ b/build/pymake/pymake/util.py
@@ -8,9 +8,9 @@ class MakeError(Exception):
     def __str__(self):
         locstr = ''
         if self.loc is not None:
-            locstr = "%s:" % (self.loc,)
+            locstr = "{}:".format(self.loc)
 
-        return "%s%s" % (locstr, self.msg)
+        return "{}{}".format(locstr, self.msg)
 
 def normaljoin(path, suffix):
     """
@@ -82,7 +82,7 @@ else:
         return str[:offset], token, str[offset + len(token):]
 
 try:
-    from __builtin__ import any
+    from builtins import any
 except ImportError:
     def any(it):
         for i in it:
@@ -90,7 +90,7 @@ except ImportError:
                 return True
         return False
 
-class _MostUsedItem(object):
+class _MostUsedItem:
     __slots__ = ('key', 'o', 'count')
 
     def __init__(self, key):
@@ -101,7 +101,7 @@ class _MostUsedItem(object):
     def __repr__(self):
         return "MostUsedItem(key=%r, count=%i, o=%r)" % (self.key, self.count, self.o)
 
-class MostUsedCache(object):
+class MostUsedCache:
     def __init__(self, capacity, creationfunc, verifyfunc):
         self.capacity = capacity
         self.cfunc = creationfunc
@@ -138,7 +138,7 @@ class MostUsedCache(object):
         return item.o
 
     def verify(self):
-        for k, v in self.d.iteritems():
+        for k, v in self.d.items():
             if v.o:
                 assert v in self.active
             else:
diff --git a/build/pymake/tests/datatests.py b/build/pymake/tests/datatests.py
index 513028b0b2..f42efbf6ee 100644
--- a/build/pymake/tests/datatests.py
+++ b/build/pymake/tests/datatests.py
@@ -4,7 +4,7 @@ import re
 from cStringIO import StringIO
 
 def multitest(cls):
-    for name in cls.testdata.iterkeys():
+    for name in cls.testdata.keys():
         def m(self, name=name):
             return self.runSingle(*self.testdata[name])
 
@@ -20,7 +20,7 @@ class SplitWordsTest(unittest.TestCase):
     def runTest(self):
         for s, e in self.testdata:
             w = s.split()
-            self.assertEqual(w, e, 'splitwords(%r)' % (s,))
+            self.assertEqual(w, e, 'splitwords({!r})'.format(s))
 
 class GetPatSubstTest(unittest.TestCase):
     testdata = (
@@ -37,9 +37,9 @@ class GetPatSubstTest(unittest.TestCase):
         for s, r, d, e in self.testdata:
             words = d.split()
             p = pymake.data.Pattern(s)
-            a = ' '.join((p.subst(r, word, False)
-                          for word in words))
-            self.assertEqual(a, e, 'Pattern(%r).subst(%r, %r)' % (s, r, d))
+            a = ' '.join(p.subst(r, word, False)
+                          for word in words)
+            self.assertEqual(a, e, 'Pattern({!r}).subst({!r}, {!r})'.format(s, r, d))
 
 class LRUTest(unittest.TestCase):
     # getkey, expected, funccount, debugitems
@@ -63,7 +63,7 @@ class LRUTest(unittest.TestCase):
         c = pymake.util.LRUCache(3, self.spaceFunc, lambda k, v: k % 2)
         self.assertEqual(tuple(c.debugitems()), ())
 
-        for i in xrange(0, len(self.expected)):
+        for i in range(0, len(self.expected)):
             k, e, fc, di = self.expected[i]
 
             v = c.get(k)
diff --git a/build/pymake/tests/formattingtests.py b/build/pymake/tests/formattingtests.py
index 7aad6d4cc1..2ab203a9ae 100644
--- a/build/pymake/tests/formattingtests.py
+++ b/build/pymake/tests/formattingtests.py
@@ -94,7 +94,7 @@ class StringExpansionTest(TestBase):
 
         e = StringExpansion('this is # not a comment', None)
         self.assertEqual(e.to_source(escape_comments=True),
-                         'this is \# not a comment')
+                         r'this is \# not a comment')
 
     def test_empty(self):
         e = StringExpansion('', None)
@@ -253,7 +253,7 @@ class MakefileCorupusTest(TestBase):
                 continue
 
             source = None
-            with open(makefile, 'rU') as fh:
+            with open(makefile) as fh:
                 source = fh.read()
 
             try:
@@ -277,7 +277,7 @@ class MakefileCorupusTest(TestBase):
 
             self.assertEqual(len(statements), len(new_statements))
 
-            for i in xrange(0, len(statements)):
+            for i in range(0, len(statements)):
                 original = statements[i]
                 formatted = new_statements[i]
 
diff --git a/build/pymake/tests/parsertests.py b/build/pymake/tests/parsertests.py
index ab6406be0f..0f6487fe5a 100644
--- a/build/pymake/tests/parsertests.py
+++ b/build/pymake/tests/parsertests.py
@@ -5,7 +5,7 @@ import logging
 from cStringIO import StringIO
 
 def multitest(cls):
-    for name in cls.testdata.iterkeys():
+    for name in cls.testdata.keys():
         def m(self, name=name):
             return self.runSingle(*self.testdata[name])
 
@@ -15,7 +15,7 @@ def multitest(cls):
 class TestBase(unittest.TestCase):
     def assertEqual(self, a, b, msg=""):
         """Actually print the values which weren't equal, if things don't work out!"""
-        unittest.TestCase.assertEqual(self, a, b, "%s got %r expected %r" % (msg, a, b))
+        unittest.TestCase.assertEqual(self, a, b, "{} got {!r} expected {!r}".format(msg, a, b))
 
 class DataTest(TestBase):
     testdata = {
@@ -86,7 +86,7 @@ class IterTest(TestBase):
             ),
         'makeescapedcomment': (
             pymake.parser.itermakefilechars,
-            "VAR = val \# escaped hash",
+            r"VAR = val \# escaped hash",
             "VAR = val # escaped hash"
             ),
         'makeescapedslash': (
@@ -116,8 +116,8 @@ class IterTest(TestBase):
             ),
         'commandcomment': (
             pymake.parser.itercommandchars,
-            "echo boo \# comment",
-            "echo boo \# comment",
+            r"echo boo \# comment",
+            r"echo boo \# comment",
             ),
         'commandcontinue': (
             pymake.parser.itercommandchars,
@@ -134,7 +134,7 @@ class IterTest(TestBase):
         self.assertEqual(actual, expected)
 
         if ifunc == pymake.parser.itermakefilechars:
-            print "testing %r" % expected
+            print("testing %r" % expected)
             self.assertEqual(pymake.parser.flattenmakesyntax(d, 0), expected)
 
 multitest(IterTest)
@@ -206,18 +206,18 @@ class MakeSyntaxTest(TestBase):
 
     def compareRecursive(self, actual, expected, path):
         self.assertEqual(len(actual), len(expected),
-                         "compareRecursive: %s %r" % (path, actual))
-        for i in xrange(0, len(actual)):
+                         "compareRecursive: {} {!r}".format(path, actual))
+        for i in range(0, len(actual)):
             ipath = path + [i]
 
             a, isfunc = actual[i]
             e = expected[i]
             if isinstance(e, str):
-                self.assertEqual(a, e, "compareRecursive: %s" % (ipath,))
+                self.assertEqual(a, e, "compareRecursive: {}".format(ipath))
             else:
                 self.assertEqual(type(a), getattr(pymake.functions, e['type']),
-                                 "compareRecursive: %s" % (ipath,))
-                for k, v in e.iteritems():
+                                 "compareRecursive: {}".format(ipath))
+                for k, v in e.items():
                     if k == 'type':
                         pass
                     elif k[0] == '[':
@@ -229,7 +229,7 @@ class MakeSyntaxTest(TestBase):
                         proppath = ipath + [item]
                         self.compareRecursive(getattr(a, item), v, proppath)
                     else:
-                        raise Exception("Unexpected property at %s: %s" % (ipath, k))
+                        raise Exception("Unexpected property at {}: {}".format(ipath, k))
 
     def runSingle(self, s, startat, stopat, stopoffset, expansion):
         d = pymake.parser.Data.fromstring(s, pymake.parserdata.Location('testdata', 1, 0))
@@ -264,7 +264,7 @@ class VariableTest(TestBase):
 
         m = pymake.data.Makefile()
         stmts.execute(m)
-        for k, v in self.expected.iteritems():
+        for k, v in self.expected.items():
             flavor, source, val = m.variables.get(k)
             if val is None:
                 self.assertEqual(val, v, 'variable named %s' % k)
diff --git a/build/pymake/tests/runtests.py b/build/pymake/tests/runtests.py
index ab149ecfb1..6ea0b91a97 100644
--- a/build/pymake/tests/runtests.py
+++ b/build/pymake/tests/runtests.py
@@ -78,15 +78,15 @@ def runTest(makefile, make, logfile, options):
     logfd.close()
 
     if stdout.find('TEST-FAIL') != -1:
-        print stdout
+        print(stdout)
         return False, "FAIL (TEST-FAIL printed)"
 
     if options['grepfor'] and stdout.find(options['grepfor']) == -1:
-        print stdout
+        print(stdout)
         return False, "FAIL (%s not in output)" % options['grepfor']
 
     if options['returncode'] == 0 and stdout.find('TEST-PASS') == -1:
-        print stdout
+        print(stdout)
         return False, 'FAIL (No TEST-PASS printed)'
 
     if options['returncode'] != 0:
@@ -94,7 +94,7 @@ def runTest(makefile, make, logfile, options):
 
     return True, 'PASS'
 
-print "%-30s%-28s%-28s" % ("Test:", "gmake:", "pymake:")
+print("%-30s%-28s%-28s" % ("Test:", "gmake:", "pymake:"))
 
 gmakefails = 0
 pymakefails = 0
@@ -153,7 +153,7 @@ for makefile in makefiles:
         elif key == 'skip':
             d['skip'] = True
         else:
-            print >>sys.stderr, "%s: Unexpected #T key: %s" % (makefile, key)
+            print("%s: Unexpected #T key: %s" % (makefile, key), file=sys.stderr)
             sys.exit(1)
 
     mdata.close()
@@ -190,12 +190,11 @@ for makefile in makefiles:
         else:
             pymakemsg = "OK (known fail)"
 
-    print "%-30.30s%-28.28s%-28.28s" % (os.path.basename(makefile),
+    print("%-30.30s%-28.28s%-28.28s" % (os.path.basename(makefile),)
                                         gmakemsg, pymakemsg)
 
-print
-print "Summary:"
-print "%-30s%-28s%-28s" % ("", "gmake:", "pymake:")
+print(print "Summary:")
+print("%-30s%-28s%-28s" % ("", "gmake:", "pymake:"))
 
 if gmakefails == 0:
     gmakemsg = 'PASS'
@@ -207,7 +206,7 @@ if pymakefails == 0:
 else:
     pymakemsg = 'FAIL (%i failures)' % pymakefails
 
-print "%-30.30s%-28.28s%-28.28s" % ('', gmakemsg, pymakemsg)
+print("%-30.30s%-28.28s%-28.28s" % ('', gmakemsg, pymakemsg))
 
 shutil.rmtree(opts.tempdir)
 
diff --git a/build/release/info.py b/build/release/info.py
index 7e7a30bcea..c3c3ec9921 100644
--- a/build/release/info.py
+++ b/build/release/info.py
@@ -4,7 +4,7 @@ from os import path
 import re
 import shutil
 import sys
-from urllib2 import urlopen
+from urllib.request import urlopen
 
 from release.paths import makeCandidatesDir
 
@@ -13,7 +13,7 @@ log = logging.getLogger(__name__)
 
 # If version has two parts with no trailing specifiers like "rc", we
 # consider it a "final" release for which we only create a _RELEASE tag.
-FINAL_RELEASE_REGEX = "^\d+\.\d+$"
+FINAL_RELEASE_REGEX = r"^\d+\.\d+$"
 
 
 class ConfigError(Exception):
@@ -50,7 +50,7 @@ def findOldBuildIDs(product, version, buildNumber, platforms,
                 id = getBuildID(platform, product, version, n, nightlyDir,
                                 server)
                 ids[platform].append(id)
-            except Exception, e:
+            except Exception as e:
                 log.error("Hit exception: %s" % e)
     return ids
 
@@ -62,7 +62,7 @@ def getReleaseConfigName(product, branch, version=None, staging=False):
     if product == 'thunderbird' and 'esr17' in branch and version and 'esr' not in version:
         cfg = 'release-thunderbird-comm-release.py'
     else:
-        cfg = 'release-%s-%s.py' % (product, branch)
+        cfg = 'release-{}-{}.py'.format(product, branch)
     if staging:
         cfg = 'staging_%s' % cfg
     return cfg
@@ -87,15 +87,15 @@ def readBranchConfig(dir, localconfig, branch, required=[]):
 
 def readConfig(configfile, keys=[], required=[]):
     c = {}
-    execfile(configfile, c)
+    exec(compile(open(configfile, "rb").read(), configfile, 'exec'), c)
     for k in keys:
         c = c[k]
-    items = c.keys()
+    items = list(c.keys())
     err = False
     for key in required:
         if key not in items:
             err = True
-            log.error("Required item `%s' missing from %s" % (key, c))
+            log.error("Required item `{}' missing from {}".format(key, c))
     if err:
         raise ConfigError("Missing at least one item in config, see above")
     return c
@@ -108,7 +108,7 @@ def isFinalRelease(version):
 def getBaseTag(product, version):
     product = product.upper()
     version = version.replace('.', '_')
-    return '%s_%s' % (product, version)
+    return '{}_{}'.format(product, version)
 
 
 def getTags(baseTag, buildNumber, buildTag=True):
@@ -127,13 +127,13 @@ def getReleaseTag(tag):
 
 
 def generateRelbranchName(version, prefix='GECKO'):
-    return '%s%s_%s_RELBRANCH' % (
+    return '{}{}_{}_RELBRANCH'.format(
         prefix, version.replace('.', ''),
         datetime.utcnow().strftime('%Y%m%d%H'))
 
 
 def getReleaseName(product, version, buildNumber):
-    return '%s-%s-build%s' % (product.title(), version, str(buildNumber))
+    return '{}-{}-build{}'.format(product.title(), version, str(buildNumber))
 
 
 def getRepoMatchingBranch(branch, sourceRepositories):
@@ -161,7 +161,7 @@ def fileInfo(filepath, product):
         # Mozilla 1.9.0 style (aka 'short') paths
         # e.g. firefox-3.0.12.en-US.win32.complete.mar
         filename = os.path.basename(filepath)
-        m = re.match("^(%s)-([0-9.]+)\.([-a-zA-Z]+)\.(win32)\.(complete|installer)\.(mar|exe)$" % product, filename)
+        m = re.match(r"^(%s)-([0-9.]+)\.([-a-zA-Z]+)\.(win32)\.(complete|installer)\.(mar|exe)$" % product, filename)
         if not m:
             raise ValueError("Could not parse: %s" % filename)
         return {'product': m.group(1),
@@ -180,7 +180,7 @@ def fileInfo(filepath, product):
         ret = {'pathstyle': 'long'}
         if filepath.endswith('.mar'):
             ret['format'] = 'mar'
-            m = re.search("update/(win32|linux-i686|linux-x86_64|mac|mac64)/([-a-zA-Z]+)/(%s)-(\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?)\.(complete)\.mar" % product, filepath)
+            m = re.search(r"update/(win32|linux-i686|linux-x86_64|mac|mac64)/([-a-zA-Z]+)/(%s)-(\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?)\.(complete)\.mar" % product, filepath)
             if not m:
                 raise ValueError("Could not parse: %s" % filepath)
             ret['platform'] = m.group(1)
@@ -196,7 +196,7 @@ def fileInfo(filepath, product):
             # that we can't catch them in the same regexp
             if filepath.find('win32-EUballot') != -1:
                 ret['platform'] = 'win32'
-                m = re.search("(win32-EUballot/)([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+\d+)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
+                m = re.search(r"(win32-EUballot/)([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+\d+)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
                 if not m:
                     raise ValueError("Could not parse: %s" % filepath)
                 ret['leading_path'] = m.group(1)
@@ -204,7 +204,7 @@ def fileInfo(filepath, product):
                 ret['product'] = m.group(3).lower()
                 ret['version'] = m.group(4)
             else:
-                m = re.search("(partner-repacks/[-a-zA-Z0-9_]+/|)(win32|mac|linux-i686)/([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
+                m = re.search(r"(partner-repacks/[-a-zA-Z0-9_]+/|)(win32|mac|linux-i686)/([-a-zA-Z]+)/((?i)%s) Setup (\d+\.\d+(?:\.\d+)?(?:\w+(?:\d+)?)?(?:\ \w+\ \d+)?)\.exe" % product, filepath)
                 if not m:
                     raise ValueError("Could not parse: %s" % filepath)
                 ret['leading_path'] = m.group(1)
diff --git a/build/release/sanity.py b/build/release/sanity.py
index aba8559894..70d745f471 100644
--- a/build/release/sanity.py
+++ b/build/release/sanity.py
@@ -1,10 +1,11 @@
 import difflib
 import logging
 import re
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 from util.commands import run_cmd, get_output
 from util.hg import get_repo_name, make_hg_url
 from subprocess import CalledProcessError
+import six
 
 log = logging.getLogger(__name__)
 
@@ -44,7 +45,7 @@ def get_buildbot_username_param():
 
 def sendchange(branch, revision, username, master, products):
     """Send the change to buildbot to kick off the release automation"""
-    if isinstance(products, basestring):
+    if isinstance(products, str):
         products = [products]
     cmd = [
         'buildbot',
@@ -107,7 +108,7 @@ def verify_mozconfigs(mozconfig_pair, nightly_mozconfig_pair, platform,
                             mozconfigWhitelist['nightly'][platform]:
                         continue
                     else:
-                        log.warning("%s not in %s %s!" % (
+                        log.warning("{} not in {} {}!".format(
                             clean_line, platform,
                             mozconfigWhitelist['nightly'][platform]))
             else:
diff --git a/build/subconfigure.py b/build/subconfigure.py
index 6c152f4065..4e54a9a268 100644
--- a/build/subconfigure.py
+++ b/build/subconfigure.py
@@ -131,11 +131,11 @@ def maybe_clear_cache(data):
         is_set = cache.get('ac_cv_env_%s_set' % precious) == 'set'
         value = cache.get('ac_cv_env_%s_value' % precious) if is_set else None
         if value != env.get(precious):
-            print 'Removing %s because of %s value change from:' \
-                % (data['cache-file'], precious)
-            print '  %s' % (value if value is not None else 'undefined')
-            print 'to:'
-            print '  %s' % env.get(precious, 'undefined')
+            print('Removing %s because of %s value change from:'
+                  % (data['cache-file'], precious))
+            print('  %s' % (value if value is not None else 'undefined'))
+            print('to:')
+            print('  %s' % env.get(precious, 'undefined'))
             os.remove(data['cache-file'])
             return True
     return False
@@ -199,9 +199,12 @@ def prepare(srcdir, objdir, shell, args):
     data_file = os.path.join(objdir, CONFIGURE_DATA)
     previous_args = None
     if os.path.exists(data_file):
-        with open(data_file, 'rb') as f:
-            data = pickle.load(f)
-            previous_args = data['args']
+        try:
+            with open(data_file, 'rb') as f:
+                data = pickle.load(f)
+                previous_args = data['args']
+        except (EOFError, pickle.UnpicklingError):
+            pass
 
     # Msys likes to break environment variables and command line arguments,
     # so read those from stdin, as they are passed from the configure script
@@ -221,7 +224,7 @@ def prepare(srcdir, objdir, shell, args):
                 environ[var] = os.environ[var]
         args = data['args']
     else:
-        environ = os.environ
+        environ = dict(os.environ)
 
     args, others = parser.parse_known_args(args)
 
@@ -333,14 +336,20 @@ def run(objdir):
         # We're going to run it ourselves.
         command += ['--no-create']
 
-        print prefix_lines('configuring', relobjdir)
-        print prefix_lines('running %s' % ' '.join(command[:-1]), relobjdir)
+        print(prefix_lines('configuring', relobjdir))
+        print(prefix_lines('running %s' % ' '.join(command[:-1]), relobjdir))
         sys.stdout.flush()
         try:
-            output += subprocess.check_output(command,
+            cmd_out = subprocess.check_output(command,
                 stderr=subprocess.STDOUT, cwd=objdir, env=data['env'])
+            if isinstance(cmd_out, bytes):
+                cmd_out = cmd_out.decode('utf-8', errors='replace')
+            output += cmd_out
         except subprocess.CalledProcessError as e:
-            return relobjdir, e.returncode, e.output
+            err_out = e.output
+            if isinstance(err_out, bytes):
+                err_out = err_out.decode('utf-8', errors='replace')
+            return relobjdir, e.returncode, err_out
 
         # Leave config.status with a new timestamp if configure is newer than
         # its original mtime.
@@ -368,15 +377,21 @@ def run(objdir):
 
     if not skip_config_status:
         if skip_configure:
-            print prefix_lines('running config.status', relobjdir)
+            print(prefix_lines('running config.status', relobjdir))
             sys.stdout.flush()
         try:
-            output += subprocess.check_output([data['shell'], '-c',
+            cs_out = subprocess.check_output([data['shell'], '-c',
                 './config.status'], stderr=subprocess.STDOUT, cwd=objdir,
                 env=data['env'])
+            if isinstance(cs_out, bytes):
+                cs_out = cs_out.decode('utf-8', errors='replace')
+            output += cs_out
         except subprocess.CalledProcessError as e:
             ret = e.returncode
-            output += e.output
+            err_out2 = e.output
+            if isinstance(err_out2, bytes):
+                err_out2 = err_out2.decode('utf-8', errors='replace')
+            output += err_out2
 
         for f in contents:
             f.update_time()
@@ -395,9 +410,9 @@ def subconfigure(args):
     args, others = parser.parse_known_args(args)
     subconfigures = args.subconfigures
     if args.list:
-        subconfigures.extend(open(args.list, 'rb').read().splitlines())
+        subconfigures.extend(open(args.list, 'r').read().splitlines())
     if args.skip:
-        skips = set(open(args.skip, 'rb').read().splitlines())
+        skips = set(open(args.skip, 'r').read().splitlines())
         subconfigures = [s for s in subconfigures if s not in skips]
 
     if not subconfigures:
@@ -410,7 +425,7 @@ def subconfigure(args):
     pool = Pool(len(subconfigures))
     for relobjdir, returncode, output in \
             pool.imap_unordered(run, subconfigures):
-        print prefix_lines(output, relobjdir)
+        print(prefix_lines(output, relobjdir))
         sys.stdout.flush()
         ret = max(returncode, ret)
         if ret:
diff --git a/build/submit_telemetry_data.py b/build/submit_telemetry_data.py
index 918d840b7b..58c6d203fa 100644
--- a/build/submit_telemetry_data.py
+++ b/build/submit_telemetry_data.py
@@ -36,7 +36,7 @@ def submit_telemetry_data(statedir):
         path = os.path.join(outgoing, filename)
         if os.path.isdir(path) or not path.endswith('.json'):
             continue
-        with open(path, 'r') as f:
+        with open(path) as f:
             data = f.read()
             try:
                 r = session.post(BUILD_TELEMETRY_SERVER, data=data,
diff --git a/build/upload.py b/build/upload.py
index c6bc10429b..7b9d4d7745 100644
--- a/build/upload.py
+++ b/build/upload.py
@@ -104,10 +104,10 @@ def DoSSHCommand(command, user, host, port=None, ssh_key=None):
         try:
             output = f(cmdline, stderr=STDOUT).strip()
         except CalledProcessError as e:
-            print "failed ssh command output:"
-            print '=' * 20
-            print e.output
-            print '=' * 20
+            print("failed ssh command output:")
+            print('=' * 20)
+            print(e.output)
+            print('=' * 20)
             raise
         return output
 
@@ -118,7 +118,7 @@ def DoSCPFile(file, remote_path, user, host, port=None, ssh_key=None,
     """Upload file to user@host:remote_path using scp. Optionally use
     port and ssh_key, if provided."""
     if log:
-        print 'Uploading %s' % file
+        print('Uploading %s' % file)
     cmdline = ["scp"]
     AppendOptionalArgsToSSHCommandline(cmdline, port, ssh_key)
     cmdline.extend([WindowsPathToMsysPath(file),
@@ -221,7 +221,7 @@ def UploadFiles(user, host, path, files, verbose=False, port=None, ssh_key=None,
     if not host or not user:
         return {}
     if (not path and not upload_to_temp_dir) or (path and upload_to_temp_dir):
-        print "One (and only one of UPLOAD_PATH or UPLOAD_TO_TEMP must be " + \
+        print("One (and only one of UPLOAD_PATH or UPLOAD_TO_TEMP must be " + \)
                 "defined."
         sys.exit(1)
 
@@ -269,18 +269,18 @@ def UploadFiles(user, host, path, files, verbose=False, port=None, ssh_key=None,
 
         if post_upload_command is not None:
             if verbose:
-                print "Running post-upload command: " + post_upload_command
+                print("Running post-upload command: " + post_upload_command)
             file_list = '"' + '" "'.join(remote_files) + '"'
             output = DoSSHCommand('%s "%s" %s' % (post_upload_command, path, file_list), user, host, port=port, ssh_key=ssh_key)
             # We print since mozharness may parse URLs from the output stream.
-            print output
+            print(output)
             properties = GetUrlProperties(output, package)
     finally:
         if upload_to_temp_dir:
             DoSSHCommand("rm -rf %s" % path, user, host, port=port,
                          ssh_key=ssh_key)
     if verbose:
-        print "Upload complete"
+        print("Upload complete")
     return properties
 
 def CopyFilesLocally(path, files, verbose=False, base_path=None, package=None):
@@ -299,7 +299,7 @@ def CopyFilesLocally(path, files, verbose=False, base_path=None, package=None):
         if not os.path.exists(target_path):
             os.makedirs(target_path)
         if verbose:
-            print "Copying " + file + " to " + target_path
+            print("Copying " + file + " to " + target_path)
         shutil.copy(file, target_path)
 
 def WriteProperties(files, properties_file, url_properties, package):
@@ -341,20 +341,20 @@ if __name__ == '__main__':
                       help="Name of the main package.")
     (options, args) = parser.parse_args()
     if len(args) < 1:
-        print "You must specify at least one file to upload"
+        print("You must specify at least one file to upload")
         sys.exit(1)
     if not options.properties_file:
-        print "You must specify a --properties-file"
+        print("You must specify a --properties-file")
         sys.exit(1)
 
     if host == "localhost":
         if upload_to_temp_dir:
-            print "Cannot use UPLOAD_TO_TEMP with UPLOAD_HOST=localhost"
+            print("Cannot use UPLOAD_TO_TEMP with UPLOAD_HOST=localhost")
             sys.exit(1)
         if post_upload_command:
             # POST_UPLOAD_COMMAND is difficult to extract from the mozharness
             # scripts, so just ignore it until it's no longer used anywhere
-            print "Ignoring POST_UPLOAD_COMMAND with UPLOAD_HOST=localhost"
+            print("Ignoring POST_UPLOAD_COMMAND with UPLOAD_HOST=localhost")
 
     try:
         if host == "localhost":
@@ -371,5 +371,5 @@ if __name__ == '__main__':
 
             WriteProperties(args, options.properties_file, url_properties, options.package)
     except IOError, (strerror):
-        print strerror
+        print(strerror)
         sys.exit(1)
diff --git a/build/util/count_ctors.py b/build/util/count_ctors.py
index 6a3a870685..58e45dc78a 100644
--- a/build/util/count_ctors.py
+++ b/build/util/count_ctors.py
@@ -1,4 +1,3 @@
-
 #!/usr/bin/python
 import json
 import re
@@ -36,7 +35,7 @@ def count_ctors(filename):
         # Even if we have .ctors, we shouldn't have any constructors in .ctors.
         # Complain if .ctors does not look how we expect it to.
         if have_ctors and n_ctors_ctors != 0:
-            print >>sys.stderr, "Unexpected .ctors contents for", filename
+            print("Unexpected .ctors contents for", filename, file=sys.stderr)
             sys.exit(1)
         return n_init_array_ctors
     if have_ctors:
@@ -44,7 +43,7 @@ def count_ctors(filename):
 
     # We didn't find anything; somebody switched initialization mechanisms on
     # us, or the binary is completely busted.  Complain either way.
-    print >>sys.stderr, "Couldn't find .init_array or .ctors in", filename
+    print("Couldn't find .init_array or .ctors in", filename, file=sys.stderr)
     sys.exit(1)
 
 if __name__ == '__main__':
@@ -60,5 +59,5 @@ if __name__ == '__main__':
                 }]}
             ]
         }
-        print "PERFHERDER_DATA: %s" % json.dumps(perfherder_data)
+        print("PERFHERDER_DATA: %s" % json.dumps(perfherder_data))
 
diff --git a/build/util/hg.py b/build/util/hg.py
index c76c8ef033..5656a28055 100644
--- a/build/util/hg.py
+++ b/build/util/hg.py
@@ -2,8 +2,8 @@
 import os
 import re
 import subprocess
-from urlparse import urlsplit
-from ConfigParser import RawConfigParser
+from urllib.parse import urlsplit
+from configparser import RawConfigParser
 
 from util.commands import run_cmd, get_output, remove_path
 from util.retry import retry
@@ -34,7 +34,7 @@ def make_hg_url(hgHost, repoPath, protocol='https', revision=None,
                 filename=None):
     """construct a valid hg url from a base hg url (hg.mozilla.org),
     repoPath, revision and possible filename"""
-    base = '%s://%s' % (protocol, hgHost)
+    base = '{}://{}'.format(protocol, hgHost)
     repo = '/'.join(p.strip('/') for p in [base, repoPath])
     if not filename:
         if not revision:
@@ -88,7 +88,7 @@ def hg_ver():
     """Returns the current version of hg, as a tuple of
     (major, minor, build)"""
     ver_string = get_output(['hg', '-q', 'version'])
-    match = re.search("\(version ([0-9.]+)\)", ver_string)
+    match = re.search(r"\(version ([0-9.]+)\)", ver_string)
     if match:
         bits = match.group(1).split(".")
         if len(bits) < 3:
@@ -105,7 +105,7 @@ def purge(dest):
     try:
         run_cmd(['hg', '--config', 'extensions.purge=', 'purge',
                  '-a', '--all', dest], cwd=dest)
-    except subprocess.CalledProcessError, e:
+    except subprocess.CalledProcessError as e:
         log.debug('purge failed: %s' % e)
         raise
 
@@ -306,7 +306,7 @@ def out(src, remote, **kwargs):
                     branch = "default"
                 revs.append((rev, branch))
             return revs
-        except subprocess.CalledProcessError, inst:
+        except subprocess.CalledProcessError as inst:
             # In some situations, some versions of Mercurial return "1"
             # if no changes are found, so we need to ignore this return code
             if inst.returncode == 1:
@@ -500,7 +500,7 @@ def apply_and_push(localrepo, remote, changer, max_attempts=10,
             push(src=localrepo, remote=remote, ssh_username=ssh_username,
                  ssh_key=ssh_key, force=force)
             return
-        except subprocess.CalledProcessError, e:
+        except subprocess.CalledProcessError as e:
             log.debug("Hit error when trying to push: %s" % str(e))
             if n == max_attempts:
                 log.debug("Tried %d times, giving up" % max_attempts)
@@ -515,7 +515,7 @@ def apply_and_push(localrepo, remote, changer, max_attempts=10,
             try:
                 run_cmd(['hg', '--config', 'ui.merge=internal:merge',
                          'rebase'], cwd=localrepo)
-            except subprocess.CalledProcessError, e:
+            except subprocess.CalledProcessError as e:
                 log.debug("Failed to rebase: %s" % str(e))
                 update(localrepo, branch=branch)
                 for r in reversed(new_revs):
diff --git a/build/valgrind/mach_commands.py b/build/valgrind/mach_commands.py
index 8109f0784a..d3e28e1daa 100644
--- a/build/valgrind/mach_commands.py
+++ b/build/valgrind/mach_commands.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import logging
 import os
diff --git a/build/valgrind/output_handler.py b/build/valgrind/output_handler.py
index df24ff28be..30be3a180d 100644
--- a/build/valgrind/output_handler.py
+++ b/build/valgrind/output_handler.py
@@ -2,12 +2,11 @@
 # 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 print_function, unicode_literals
 
 import logging
 import re
 
-class OutputHandler(object):
+class OutputHandler:
     '''
     A class for handling Valgrind output.
 
diff --git a/build/variables.py b/build/variables.py
index de0903af28..dc6205d7cc 100644
--- a/build/variables.py
+++ b/build/variables.py
@@ -2,7 +2,6 @@
 # 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 print_function, unicode_literals
 
 import os
 import subprocess
@@ -90,7 +89,7 @@ def source_repo_header(output):
         output.write('#define MOZ_SOURCE_STAMP %s\n' % changeset)
 
     if repo and buildconfig.substs.get('MOZ_INCLUDE_SOURCE_INFO'):
-        source = '%s/rev/%s' % (repo, changeset)
+        source = '{}/rev/{}'.format(repo, changeset)
         output.write('#define MOZ_SOURCE_REPO %s\n' % repo)
         output.write('#define MOZ_SOURCE_URL %s\n' % source)
 
diff --git a/build/win32/autobinscope.py b/build/win32/autobinscope.py
index fdba68e0c3..bdc5d27f69 100644
--- a/build/win32/autobinscope.py
+++ b/build/win32/autobinscope.py
@@ -23,7 +23,7 @@ BINSCOPE_OUTPUT_LOGFILE = r".\binscope_xml_output.log"
 
 # usage
 if len(sys.argv) < 3:
-  print """usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]"
+  print("""usage : autobinscope.by path_to_binary path_to_symbols [log_file_path]")
 		log_file_path is optional, log will be written to .\binscope_xml_output.log by default"""
   sys.exit(0)
 
@@ -40,7 +40,7 @@ else:
 try:
   binscope_path = os.environ['BINSCOPE']
 except KeyError:
-  print "BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status."
+  print("BINSCOPE environment variable is not set, can't check DEP/ASLR etc. status.")
   sys.exit(0)
   
 try:    
@@ -53,11 +53,11 @@ try:
 
 except WindowsError, (errno, strerror): 
   if errno != 2 and errno != 3:
-    print "Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n"
+    print("Unexpected error ! \nError " + str(errno) + " : " + strerror + "\nExiting !\n")
     sys.exit(0)
   else:
-    print "Could not locate binscope at location : %s\n" % binscope_path
-    print "Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting..."
+    print("Could not locate binscope at location : %s\n" % binscope_path)
+    print("Binscope wasn't installed or the BINSCOPE env variable wasn't set correctly, skipping this check and exiting...")
     sys.exit(0)
 
 proc.wait()
@@ -66,10 +66,10 @@ output = proc.communicate()[0]
 
 # is this a PASS or a FAIL ? 
 if proc.returncode != 0:
-  print "Error count: %d" % proc.returncode
-  print "TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path
+  print("Error count: %d" % proc.returncode)
+  print("TEST-UNEXPECTED-FAIL | autobinscope.py | %s is missing a needed Windows protection, such as /GS or ASLR" % binary_path)
   logfile = open(log_file_path, "r")
   for line in logfile:
     print(line),
 else:
-  print "TEST-PASS | autobinscope.py | %s succeeded" % binary_path
+  print("TEST-PASS | autobinscope.py | %s succeeded" % binary_path)
diff --git a/build/win32/pgomerge.py b/build/win32/pgomerge.py
index 313d66870d..8d0351d960 100755
--- a/build/win32/pgomerge.py
+++ b/build/win32/pgomerge.py
@@ -39,6 +39,6 @@ def MergePGOFiles(basename, pgddir, pgcdir):
 
 if __name__ == '__main__':
   if len(sys.argv) != 3:
-      print >>sys.stderr, "Usage: pgomerge.py <binary basename> <dist/bin>"
+      print("Usage: pgomerge.py <binary basename> <dist/bin>", file=sys.stderr)
       sys.exit(1)
   MergePGOFiles(sys.argv[1], os.getcwd(), sys.argv[2])
diff --git a/build/win32/procmem.py b/build/win32/procmem.py
index 8376d07ea4..61621783f4 100644
--- a/build/win32/procmem.py
+++ b/build/win32/procmem.py
@@ -40,9 +40,9 @@ if __name__ == '__main__':
                                                     0, # no inherit
                                                     int(pid))
         if handle:
-            print "Process %s:" % pid
+            print("Process %s:" % pid)
             vsize, peak_vsize = get_vmsize(handle)
-            print "peak vsize: %d" % peak_vsize
+            print("peak vsize: %d" % peak_vsize)
             ctypes.windll.kernel32.CloseHandle(handle)
         else:
-            print "Couldn't open process %s" % pid
+            print("Couldn't open process %s" % pid)
diff --git a/build/windows_toolchain.py b/build/windows_toolchain.py
index 22e656eff3..5a8552c1e6 100644
--- a/build/windows_toolchain.py
+++ b/build/windows_toolchain.py
@@ -10,7 +10,6 @@
 # When updating behavior of this script, remember to update the docs
 # in ``build/docs/toolchains.rst``.
 
-from __future__ import absolute_import, unicode_literals
 
 import hashlib
 import os
@@ -200,7 +199,7 @@ def format_manifest(manifest):
 
 def write_zip(zip_path, prefix=None):
     """Write toolchain data to a zip file."""
-    if isinstance(prefix, unicode):
+    if isinstance(prefix, str):
         prefix = prefix.encode('utf-8')
 
     with JarWriter(file=zip_path, optimize=False, compress=5) as zip:
diff --git a/client.py b/client.py
index d832c4287d..fe10a0d61a 100755
--- a/client.py
+++ b/client.py
@@ -4,6 +4,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
+from __future__ import print_function
 LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
 HG_EXCLUSIONS = ['.hg', '.hgignore', '.hgtags']
 
@@ -22,7 +23,7 @@ if topsrcdir == '':
     topsrcdir = '.'
 
 def check_call_noisy(cmd, *args, **kwargs):
-    print "Executing command:", cmd
+    print("Executing command:", cmd)
     check_call(cmd, *args, **kwargs)
 
 def do_hg_pull(dir, repository, hg):
@@ -67,22 +68,22 @@ def do_cvs_export(modules, tag, cvsroot, cvs):
         cvs_module = module_tuple[1]
         fullpath = os.path.join(topsrcdir, module)
         if os.path.exists(fullpath):
-            print "Removing '%s'" % fullpath
+            print("Removing '%s'" % fullpath)
             shutil.rmtree(fullpath)
 
         (parent, leaf) = os.path.split(module)
-        print "CVS export begin: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
+        print("CVS export begin: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"))
         check_call_noisy([cvs, '-d', cvsroot,
                           'export', '-r', tag, '-d', leaf, cvs_module],
                          cwd=os.path.join(topsrcdir, parent))
-        print "CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
+        print("CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC"))
 
 def toggle_trailing_blank_line(depname):
   """If the trailing line is empty, then we'll delete it.
   Otherwise we'll add a blank line."""
   lines = open(depname, "r").readlines()
   if not lines:
-      print >>sys.stderr, "unexpected short file"
+      print("unexpected short file", file=sys.stderr)
       return
 
   if not lines[-1].strip():
@@ -95,7 +96,7 @@ def toggle_trailing_blank_line(depname):
 def get_trailing_blank_line_state(depname):
   lines = open(depname, "r").readlines()
   if not lines:
-      print >>sys.stderr, "unexpected short file"
+      print("unexpected short file", file=sys.stderr)
       return "no blank line"
 
   if not lines[-1].strip():
@@ -104,18 +105,18 @@ def get_trailing_blank_line_state(depname):
       return "no blank line"
 
 def update_nspr_or_nss(tag, depfile, destination, hgpath):
-  print "reverting to HG version of %s to get its blank line state" % depfile
+  print("reverting to HG version of %s to get its blank line state" % depfile)
   check_call_noisy([options.hg, 'revert', depfile])
   old_state = get_trailing_blank_line_state(depfile)
-  print "old state of %s is: %s" % (depfile, old_state)
+  print("old state of %s is: %s" % (depfile, old_state))
   do_hg_replace(destination, hgpath, tag, HG_EXCLUSIONS, options.hg)
   new_state = get_trailing_blank_line_state(depfile)
-  print "new state of %s is: %s" % (depfile, new_state)
+  print("new state of %s is: %s" % (depfile, new_state))
   if old_state == new_state:
-    print "toggling blank line in: ", depfile
+    print("toggling blank line in: ", depfile)
     toggle_trailing_blank_line(depfile)
   tag_file = destination + "/TAG-INFO"
-  print >>file(tag_file, "w"), tag
+  print(tag, file=open(tag_file, "w"))
 
 o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname")
 o.add_option("--skip-mozilla", dest="skip_mozilla",
@@ -139,7 +140,7 @@ except IndexError:
     sys.exit(2)
 
 if action in ('checkout', 'co'):
-    print >>sys.stderr, "Warning: client.py checkout is obsolete."
+    print("Warning: client.py checkout is obsolete.", file=sys.stderr)
     pass
 elif action in ('update_nspr'):
     tag, = args[1:]
diff --git a/config/MozZipFile.py b/config/MozZipFile.py
index 337fe0521b..dc7add4c3a 100644
--- a/config/MozZipFile.py
+++ b/config/MozZipFile.py
@@ -18,7 +18,7 @@ class ZipFile(zipfile.ZipFile):
   def __init__(self, file, mode="r", compression=zipfile.ZIP_STORED,
                lock = False):
     if lock:
-      assert isinstance(file, basestring)
+      assert isinstance(file, str)
       self.lockfile = lock_file(file + '.lck')
     else:
       self.lockfile = None
@@ -46,7 +46,7 @@ class ZipFile(zipfile.ZipFile):
                               date_time=time.localtime(time.time()))
       zinfo.compress_type = self.compression
       # Add some standard UNIX file access permissions (-rw-r--r--).
-      zinfo.external_attr = (0x81a4 & 0xFFFF) << 16L
+      zinfo.external_attr = (0x81a4 & 0xFFFF) << 16
     else:
       zinfo = zinfo_or_arcname
 
@@ -58,7 +58,7 @@ class ZipFile(zipfile.ZipFile):
     # as the old, reuse the existing entry.
 
     doSeek = False # store if we need to seek to the eof after overwriting
-    if self.NameToInfo.has_key(zinfo.filename):
+    if zinfo.filename in self.NameToInfo:
       # Find the last ZipInfo with our name.
       # Last, because that's catching multiple overwrites
       i = len(self.filelist)
@@ -109,14 +109,14 @@ class ZipFile(zipfile.ZipFile):
       # adjust file mode if we originally just wrote, now we rewrite
       self.fp.close()
       self.fp = open(self.filename, 'r+b')
-    all = map(lambda zi: (zi, True), self.filelist) + \
-        map(lambda zi: (zi, False), self._remove)
+    all = [(zi, True) for zi in self.filelist] + \
+        [(zi, False) for zi in self._remove]
     all.sort(lambda l, r: cmp(l[0].header_offset, r[0].header_offset))
     # empty _remove for multiple closes
     self._remove = []
 
     lengths = [all[i+1][0].header_offset - all[i][0].header_offset
-               for i in xrange(len(all)-1)]
+               for i in range(len(all)-1)]
     lengths.append(self.end - all[-1][0].header_offset)
     to_pos = 0
     for (zi, keep), length in zip(all, lengths):
diff --git a/config/check_source_count.py b/config/check_source_count.py
index e347e7a55e..7f993f0390 100755
--- a/config/check_source_count.py
+++ b/config/check_source_count.py
@@ -24,7 +24,7 @@ details = {}
 
 count = 0
 for f in files:
-    text = file(f).read()
+    text = open(f).read()
     match = re.findall(search_string, text)
     if match:
         num = len(match)
diff --git a/config/createprecomplete.py b/config/createprecomplete.py
index 3241d526b2..d70f282ace 100644
--- a/config/createprecomplete.py
+++ b/config/createprecomplete.py
@@ -56,10 +56,10 @@ def generate_precomplete(root_path):
     precomplete_file = open(precomplete_file_path, "wb")
     rel_file_path_list, rel_dir_path_list = get_build_entries(root_path)
     for rel_file_path in rel_file_path_list:
-        precomplete_file.writelines("remove \""+rel_file_path+"\"\n")
+        precomplete_file.write(("remove \""+rel_file_path+"\"\n").encode('utf-8'))
 
     for rel_dir_path in rel_dir_path_list:
-        precomplete_file.writelines("rmdir \""+rel_dir_path+"\"\n")
+        precomplete_file.write(("rmdir \""+rel_dir_path+"\"\n").encode('utf-8'))
 
     precomplete_file.close()
 
diff --git a/config/expandlibs.py b/config/expandlibs.py
index ac06c432f2..668db68bef 100644
--- a/config/expandlibs.py
+++ b/config/expandlibs.py
@@ -27,6 +27,7 @@ ${LIB_PREFIX}${ROOT}.${LIB_SUFFIX} following these rules:
   rules.
 '''
 from __future__ import with_statement
+from __future__ import print_function
 import sys, os, errno
 import expandlibs_config as conf
 
@@ -36,7 +37,7 @@ def ensureParentDir(file):
     if dir and not os.path.exists(dir):
         try:
             os.makedirs(dir)
-        except OSError, error:
+        except OSError as error:
             if error.errno != errno.EEXIST:
                 raise
 
@@ -140,4 +141,4 @@ class ExpandArgs(list):
         return [relativize(arg)]
 
 if __name__ == '__main__':
-    print " ".join(ExpandArgs(sys.argv[1:]))
+    print(" ".join(ExpandArgs(sys.argv[1:])))
diff --git a/config/expandlibs_exec.py b/config/expandlibs_exec.py
index fe9a7f6ebb..adc46a2911 100644
--- a/config/expandlibs_exec.py
+++ b/config/expandlibs_exec.py
@@ -21,6 +21,7 @@ relevant linker options to change the order in which the linker puts the
 symbols appear in the resulting binary. Only works for ELF targets.
 '''
 from __future__ import with_statement
+from __future__ import print_function
 import sys
 import os
 from expandlibs import (
@@ -305,11 +306,11 @@ class SectionFinder(object):
         return syms
 
 def print_command(out, args):
-    print >>out, "Executing: " + " ".join(args)
+    print("Executing: " + " ".join(args), file=out)
     for tmp in [f for f in args.tmp if os.path.isfile(f)]:
-        print >>out, tmp + ":"
+        print(tmp + ":", file=out)
         with open(tmp) as file:
-            print >>out, "".join(["    " + l for l in file.readlines()])
+            print("".join(["    " + l for l in file.readlines()]), file=out)
     out.flush()
 
 def main(args, proc_callback=None):
@@ -339,13 +340,13 @@ def main(args, proc_callback=None):
             proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
             if proc_callback:
                 proc_callback(proc)
-        except Exception, e:
-            print >>sys.stderr, 'error: Launching', args, ':', e
+        except Exception as e:
+            print('error: Launching', args, ':', e, file=sys.stderr)
             raise e
         (stdout, stderr) = proc.communicate()
         if proc.returncode and not options.verbose:
             print_command(sys.stderr, args)
-        sys.stderr.write(stdout)
+        sys.stderr.write(stdout.decode('utf-8', 'replace'))
         sys.stderr.flush()
         if proc.returncode:
             return proc.returncode
diff --git a/config/expandlibs_gen.py b/config/expandlibs_gen.py
index b1de63cd02..003e18f910 100644
--- a/config/expandlibs_gen.py
+++ b/config/expandlibs_gen.py
@@ -6,6 +6,7 @@
 descriptor to standard output'''
 
 from __future__ import with_statement
+from __future__ import print_function
 import sys
 import os
 import expandlibs_config as conf
@@ -38,4 +39,4 @@ if __name__ == '__main__':
 
     ensureParentDir(options.output)
     with open(options.output, 'w') as outfile:
-        print >>outfile, generate(args)
+        print(generate(args), file=outfile)
diff --git a/config/find_OOM_errors.py b/config/find_OOM_errors.py
index 16065119b7..830693885e 100644
--- a/config/find_OOM_errors.py
+++ b/config/find_OOM_errors.py
@@ -105,7 +105,7 @@ def count_lines():
 
   lines.sort()
 
-  countlog = file("../OOM_count_log", "w")
+  countlog = open("../OOM_count_log", "w")
   countlog.write("\n".join(lines))
   countlog.flush()
   countlog.close()
@@ -215,7 +215,7 @@ else:
 
 if OPTIONS.regression == None:
   # Don't use a logfile, this is automated for tinderbox.
-  log = file("../OOM_log", "w")
+  log = open("../OOM_log", "w")
 
 
 num_failures = 0
@@ -267,7 +267,7 @@ for f in files:
       # Get valgrind output for a good stack trace
       vcommand = "valgrind --dsymutil=yes -q --log-file=OOM_valgrind_log_file " + command
       run(vcommand)
-      vout = file("OOM_valgrind_log_file").read()
+      vout = open("OOM_valgrind_log_file").read()
       vout = clean_voutput(vout)
       sans_alloc_sites = remove_failed_allocation_backtraces(vout)
 
diff --git a/config/link.py b/config/link.py
index be63216a02..aa47503f0d 100644
--- a/config/link.py
+++ b/config/link.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import expandlibs_exec
 import sys
 import threading
@@ -18,7 +19,7 @@ def periodically_print_status(proc):
         time.sleep(0.5)
         idleTime += 0.5
         if idleTime > 20 * 60:
-          print "Still linking, 20 minutes passed..."
+          print("Still linking, 20 minutes passed...")
           sys.stdout.flush()
           idleTime = 0
 
@@ -42,6 +43,6 @@ def wrap_linker(args):
 
 if __name__ == "__main__":
     if len(sys.argv) < 2:
-        print >>sys.stderr, "Usage: link.py <commandline>"
+        print("Usage: link.py <commandline>", file=sys.stderr)
         sys.exit(1)
     sys.exit(wrap_linker(sys.argv[1:]))
diff --git a/config/mozunit.py b/config/mozunit.py
index 3dddf84ee4..69a3220050 100644
--- a/config/mozunit.py
+++ b/config/mozunit.py
@@ -140,7 +140,7 @@ class MockedOpen(object):
     '''
     def __init__(self, files = {}):
         self.files = {}
-        for name, content in files.iteritems():
+        for name, content in files.items():
             self.files[normcase(os.path.abspath(name))] = content
 
     def __call__(self, name, mode = 'r'):
@@ -158,19 +158,19 @@ class MockedOpen(object):
         return file
 
     def __enter__(self):
-        import __builtin__
-        self.open = __builtin__.open
+        import builtins
+        self.open = builtins.open
         self._orig_path_exists = os.path.exists
         self._orig_path_isdir = os.path.isdir
         self._orig_path_isfile = os.path.isfile
-        __builtin__.open = self
+        builtins.open = self
         os.path.exists = self._wrapped_exists
         os.path.isdir = self._wrapped_isdir
         os.path.isfile = self._wrapped_isfile
 
     def __exit__(self, type, value, traceback):
-        import __builtin__
-        __builtin__.open = self.open
+        import builtins
+        builtins.open = self.open
         os.path.exists = self._orig_path_exists
         os.path.isdir = self._orig_path_isdir
         os.path.isfile = self._orig_path_isfile
diff --git a/config/nsinstall.py b/config/nsinstall.py
index 4814133703..73dac0021d 100755
--- a/config/nsinstall.py
+++ b/config/nsinstall.py
@@ -149,7 +149,7 @@ def _nsinstall_internal(argv):
 
 # nsinstall as a native command is always UTF-8
 def nsinstall(argv):
-  return _nsinstall_internal([unicode(arg, "utf-8") for arg in argv])
+  return _nsinstall_internal([str(arg, "utf-8") for arg in argv])
 
 if __name__ == '__main__':
   # sys.argv corrupts characters outside the system code page on Windows
@@ -174,9 +174,6 @@ if __name__ == '__main__':
     argv = argv_arr[1:argc.value]
   else:
     # For consistency, do it on Unix as well
-    if sys.stdin.encoding is not None:
-      argv = [unicode(arg, sys.stdin.encoding) for arg in sys.argv]
-    else:
-      argv = [unicode(arg) for arg in sys.argv]
+    argv = [str(arg) for arg in sys.argv]
 
   sys.exit(_nsinstall_internal(argv[1:]))
diff --git a/config/printconfigsetting.py b/config/printconfigsetting.py
index ef900a6c05..e6c764019d 100644
--- a/config/printconfigsetting.py
+++ b/config/printconfigsetting.py
@@ -2,30 +2,31 @@
 # 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 print_function
 import configobj
 import sys
 import re
-from StringIO import StringIO
+from io import StringIO
 
 try:
     (file, section, key) = sys.argv[1:]
 except ValueError:
-    print "Usage: printconfigsetting.py <file> <section> <setting>"
+    print("Usage: printconfigsetting.py <file> <section> <setting>")
     sys.exit(1)
 
 with open(file) as fh:
-    content = re.sub('^\s*;', '#', fh.read(), flags=re.M)
+    content = re.sub(r'^\s*;', '#', fh.read(), flags=re.M)
 
 c = configobj.ConfigObj(StringIO(content))
 
 try:
     s = c[section]
 except KeyError:
-    print >>sys.stderr, "Section [%s] not found." % section
+    print("Section [%s] not found." % section, file=sys.stderr)
     sys.exit(1)
 
 try:
-    print s[key]
+    print(s[key])
 except KeyError:
-    print >>sys.stderr, "Key %s not found." % key
+    print("Key %s not found." % key, file=sys.stderr)
     sys.exit(1)
diff --git a/config/pythonpath.py b/config/pythonpath.py
index 0318066148..12fe6b1c73 100644
--- a/config/pythonpath.py
+++ b/config/pythonpath.py
@@ -7,9 +7,10 @@ Run a python script, adding extra directories to the python path.
 """
 
 
+from __future__ import print_function
 def main(args):
     def usage():
-        print >>sys.stderr, "pythonpath.py -I directory script.py [args...]"
+        print("pythonpath.py -I directory script.py [args...]", file=sys.stderr)
         sys.exit(150)
 
     paths = []
@@ -45,7 +46,7 @@ def main(args):
     frozenglobals['__name__'] = '__main__'
     frozenglobals['__file__'] = script
 
-    execfile(script, frozenglobals)
+    exec(compile(open(script, "rb").read(), script, 'exec'), frozenglobals)
 
 # Freeze scope here ... why this makes things work I have no idea ...
 frozenglobals = globals()
diff --git a/config/rebuild_check.py b/config/rebuild_check.py
index a6c3dc87ac..d7540c9359 100644
--- a/config/rebuild_check.py
+++ b/config/rebuild_check.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import errno
 
@@ -18,7 +19,7 @@ def rebuild_check(args):
     deps = args[1:]
     t = mtime(target)
     if t < 0:
-        print target
+        print(target)
         return
 
     newer = []
@@ -31,13 +32,13 @@ def rebuild_check(args):
             newer.append(dep)
 
     if newer and removed:
-        print 'Rebuilding %s because %s changed and %s was removed' % (target, ', '.join(newer), ', '.join(removed))
+        print('Rebuilding %s because %s changed and %s was removed' % (target, ', '.join(newer), ', '.join(removed)))
     elif newer:
-        print 'Rebuilding %s because %s changed' % (target, ', '.join(newer))
+        print('Rebuilding %s because %s changed' % (target, ', '.join(newer)))
     elif removed:
-        print 'Rebuilding %s because %s was removed' % (target, ', '.join(removed))
+        print('Rebuilding %s because %s was removed' % (target, ', '.join(removed)))
     else:
-        print 'Rebuilding %s for an unknown reason' % target
+        print('Rebuilding %s for an unknown reason' % target)
 
 if __name__ == '__main__':
     import sys
diff --git a/config/tests/unit-expandlibs.py b/config/tests/unit-expandlibs.py
index 3c7e5a44dd..e1b8775961 100644
--- a/config/tests/unit-expandlibs.py
+++ b/config/tests/unit-expandlibs.py
@@ -8,6 +8,7 @@ from shutil import rmtree
 import mozunit
 
 from UserString import UserString
+import six
 # Create a controlled configuration for use by expandlibs
 config_win = {
     'AR': 'lib',
@@ -120,8 +121,7 @@ class ReplicateTests(type):
             del dict[name]
         return type.__new__(cls, clsName, bases, dict)
 
-class TestCaseWithTmpDir(unittest.TestCase):
-    __metaclass__ = ReplicateTests
+class TestCaseWithTmpDir(six.with_metaclass(ReplicateTests, unittest.TestCase)):
     def init(self):
         self.tmpdir = os.path.abspath(mkdtemp(dir=os.curdir))
 
diff --git a/config/tests/unit-nsinstall.py b/config/tests/unit-nsinstall.py
index 2a230841a1..ea95fd2180 100644
--- a/config/tests/unit-nsinstall.py
+++ b/config/tests/unit-nsinstall.py
@@ -28,9 +28,9 @@ class TestNsinstall(unittest.TestCase):
         # Unicode strings means non-ASCII children can be deleted properly on
         # Windows
         if sys.stdin.encoding is None:
-            tmpdir = unicode(self.tmpdir)
+            tmpdir = str(self.tmpdir)
         else:
-            tmpdir = unicode(self.tmpdir, sys.stdin.encoding)
+            tmpdir = str(self.tmpdir, sys.stdin.encoding)
         rmtree(tmpdir)
 
     # utility methods for tests
diff --git a/config/tests/unitMozZipFile.py b/config/tests/unitMozZipFile.py
index f9c0419ab5..255e61dd2b 100644
--- a/config/tests/unitMozZipFile.py
+++ b/config/tests/unitMozZipFile.py
@@ -11,6 +11,7 @@ import sys
 import random
 import copy
 from string import letters
+from functools import reduce
 
 '''
 Test case infrastructure for MozZipFile.
@@ -38,7 +39,7 @@ leafs = (
   'firstdir/oneleaf',
   'seconddir/twoleaf',
   'thirddir/with/sub/threeleaf')
-_lengths = map(lambda n: n * 64, [16, 64, 80])
+_lengths = [n * 64 for n in [16, 64, 80]]
 lengths = 3
 writes = 5
 
@@ -71,7 +72,7 @@ def getid(descs):
 def getContent(length):
   'Get pseudo random content of given length.'
   rv = [None] * length
-  for i in xrange(length):
+  for i in range(length):
     rv[i] = random.choice(letters)
   return ''.join(rv)
 
@@ -136,10 +137,10 @@ class TestExtensiveStored(unittest.TestCase):
     self.failIf(badEntry, badEntry)
     zlist = zf.namelist()
     zlist.sort()
-    vlist = self.ref.keys()
+    vlist = list(self.ref.keys())
     vlist.sort()
     self.assertEqual(zlist, vlist)
-    for leaf, content in self.ref.iteritems():
+    for leaf, content in self.ref.items():
       zcontent = zf.read(leaf)
       self.assertEqual(content, zcontent)
   
@@ -158,16 +159,16 @@ class TestExtensiveStored(unittest.TestCase):
     open(self.leaf('stage', leaf), 'w').write(content)
 
 # all leafs in all lengths
-atomics = list(prod(xrange(len(leafs)), xrange(lengths)))
+atomics = list(prod(range(len(leafs)), range(lengths)))
 
 # populate TestExtensiveStore with testcases
-for w in xrange(writes):
+for w in range(writes):
   # Don't iterate over all files for the the first n passes,
   # those are redundant as long as w < lengths.
   # There are symmetries in the trailing end, too, but I don't know
   # how to reduce those out right now.
-  nonatomics = [list(prod(range(min(i,len(leafs))), xrange(lengths)))
-                for i in xrange(1, w+1)] + [atomics]
+  nonatomics = [list(prod(list(range(min(i,len(leafs)))), range(lengths)))
+                for i in range(1, w+1)] + [atomics]
   for descs in prod(*nonatomics):
     suffix = getid(descs)
     dicts = [dict(leaf=leaf, length=length) for leaf, length in descs]
@@ -181,9 +182,9 @@ for w in xrange(writes):
 # and then write all atomics again.
 # This should catch more or less all artifacts generated
 # by the final ordering step when closing the jar.
-files = [list(prod([i], xrange(lengths))) for i in xrange(len(leafs))]
+files = [list(prod([i], range(lengths))) for i in range(len(leafs))]
 allfiles = reduce(lambda l,r:l+r,
-                  [list(prod(*files[:(i+1)])) for i in xrange(len(leafs))])
+                  [list(prod(*files[:(i+1)])) for i in range(len(leafs))])
 
 for first in allfiles:
   testbasename = 'test{0}_'.format(getid(first))
diff --git a/configure.py b/configure.py
index f7392d0ffa..abf9dca9dc 100644
--- a/configure.py
+++ b/configure.py
@@ -45,11 +45,11 @@ def config_status(config):
 
     sanitized_config = {}
     sanitized_config['substs'] = {
-        k: sanitized_bools(v) for k, v in config.iteritems()
+        k: sanitized_bools(v) for k, v in config.items()
         if k not in ('DEFINES', 'non_global_defines', 'TOPSRCDIR', 'TOPOBJDIR')
     }
     sanitized_config['defines'] = {
-        k: sanitized_bools(v) for k, v in config['DEFINES'].iteritems()
+        k: sanitized_bools(v) for k, v in config['DEFINES'].items()
     }
     sanitized_config['non_global_defines'] = config['non_global_defines']
     sanitized_config['topsrcdir'] = config['TOPSRCDIR']
@@ -71,7 +71,7 @@ def config_status(config):
         ''') % {'python': config['PYTHON'], 'encoding': encoding})
         # A lot of the build backend code is currently expecting byte
         # strings and breaks in subtle ways with unicode strings. (bug 1296508)
-        for k, v in sanitized_config.iteritems():
+        for k, v in sanitized_config.items():
             fh.write('%s = encode(%s, encoding)\n' % (k, indented_repr(v)))
         fh.write("__all__ = ['topobjdir', 'topsrcdir', 'defines', "
                  "'non_global_defines', 'substs', 'mozconfig']")
@@ -88,7 +88,7 @@ def config_status(config):
     # executable permissions.
     os.chmod('config.status', 0o755)
     if config.get('MOZ_BUILD_APP') != 'js' or config.get('JS_STANDALONE'):
-        os.environ[b'WRITE_MOZINFO'] = b'1'
+        os.environ['WRITE_MOZINFO'] = '1'
         from mozbuild.config_status import config_status
 
         # Some values in sanitized_config also have more complex types, such as
@@ -99,7 +99,7 @@ def config_status(config):
 
         # A lot of the build backend code is currently expecting byte strings
         # and breaks in subtle ways with unicode strings.
-        return config_status(args=[], **encode(sanitized_config, encoding))
+        return config_status(args=[], **sanitized_config)
     return 0
 
 
diff --git a/devtools/shared/css/generated/mach_commands.py b/devtools/shared/css/generated/mach_commands.py
index 56f321a6f2..71728327ba 100644
--- a/devtools/shared/css/generated/mach_commands.py
+++ b/devtools/shared/css/generated/mach_commands.py
@@ -8,6 +8,7 @@ that uses inIDOMUtils to query the CSS properties used by the browser. This info
 is used to generate the properties-db.js file.
 """
 
+from __future__ import print_function
 import json
 import os
 import sys
@@ -97,4 +98,4 @@ class MachCommands(MachCommandBase):
         with open(destination_path, 'wb') as destination:
             destination.write(preamble + contents)
 
-        print('The database was successfully generated at ' + destination_path)
+        print(('The database was successfully generated at ' + destination_path))
diff --git a/dom/base/test/websocket_hybi/file_binary-frames_wsh.py b/dom/base/test/websocket_hybi/file_binary-frames_wsh.py
index 656d0e1890..2f9f379726 100644
--- a/dom/base/test/websocket_hybi/file_binary-frames_wsh.py
+++ b/dom/base/test/websocket_hybi/file_binary-frames_wsh.py
@@ -15,4 +15,4 @@ def web_socket_transfer_data(request):
 
 
 def all_distinct_bytes():
-    return ''.join([chr(i) for i in xrange(256)])
+    return ''.join([chr(i) for i in range(256)])
diff --git a/dom/base/test/websocket_hybi/file_check-binary-messages_wsh.py b/dom/base/test/websocket_hybi/file_check-binary-messages_wsh.py
index 024e3f4d07..c63ca45f3a 100644
--- a/dom/base/test/websocket_hybi/file_check-binary-messages_wsh.py
+++ b/dom/base/test/websocket_hybi/file_check-binary-messages_wsh.py
@@ -18,4 +18,4 @@ def web_socket_transfer_data(request):
 
 
 def all_distinct_bytes():
-    return ''.join([chr(i) for i in xrange(256)])
+    return ''.join([chr(i) for i in range(256)])
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 17e5502504..99fe625672 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -13,6 +13,7 @@ import functools
 
 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLInterfaceMember, IDLUndefinedValue, IDLEmptySequenceValue, IDLDictionary
 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, getAllTypes, Descriptor, MemberIsUnforgeable, iteratorNativeType
+from functools import reduce
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED BY Codegen.py - DO NOT EDIT */\n\n"
@@ -1117,13 +1118,12 @@ class CGHeaders(CGWrapper):
 
         declareIncludes = set(declareIncludes)
 
-        def addHeadersForType((t, dictionary)):
+        def addHeadersForType(xxx_todo_changeme):
             """
             Add the relevant headers for this type.  We use dictionary, if
             passed, to decide what to do with interface types.
             """
-            # Dictionaries have members that need to be actually
-            # declared, not just forward-declared.
+            (t, dictionary) = xxx_todo_changeme
             if dictionary:
                 headerSet = declareIncludes
             else:
@@ -1197,9 +1197,9 @@ class CGHeaders(CGWrapper):
                 # parametrized over, if needed.
                 addHeadersForType((t.inner, dictionary))
 
-        map(addHeadersForType,
+        list(map(addHeadersForType,
             getAllTypes(descriptors + callbackDescriptors, dictionaries,
-                        callbacks))
+                        callbacks)))
 
         # Now make sure we're not trying to include the header from inside itself
         declareIncludes.discard(prefix + ".h")
@@ -2068,8 +2068,7 @@ class MemberCondition:
         if nonExposedGlobals:
             # Nonempty set
             self.nonExposedGlobals = " | ".join(
-                map(lambda g: "GlobalNames::%s" % g,
-                    sorted(nonExposedGlobals)))
+                ["GlobalNames::%s" % g for g in sorted(nonExposedGlobals)])
         else:
             self.nonExposedGlobals = "0"
 
@@ -4677,7 +4676,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
                                         declArgs=declArgs)
 
     def incrementNestingLevel():
-        if nestingLevel is "":
+        if nestingLevel == "":
             return 1
         return nestingLevel + 1
 
@@ -4999,7 +4998,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         memberTypes = type.flatMemberTypes
         names = []
 
-        interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
+        interfaceMemberTypes = [t for t in memberTypes if t.isNonCallbackInterface()]
         if len(interfaceMemberTypes) > 0:
             interfaceObject = []
             for memberType in interfaceMemberTypes:
@@ -5013,7 +5012,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             interfaceObject = None
 
-        sequenceObjectMemberTypes = filter(lambda t: t.isSequence(), memberTypes)
+        sequenceObjectMemberTypes = [t for t in memberTypes if t.isSequence()]
         if len(sequenceObjectMemberTypes) > 0:
             assert len(sequenceObjectMemberTypes) == 1
             name = getUnionMemberName(sequenceObjectMemberTypes[0])
@@ -5024,7 +5023,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             sequenceObject = None
 
-        dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
+        dateObjectMemberTypes = [t for t in memberTypes if t.isDate()]
         if len(dateObjectMemberTypes) > 0:
             assert len(dateObjectMemberTypes) == 1
             memberType = dateObjectMemberTypes[0]
@@ -5036,7 +5035,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             dateObject = None
 
-        callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
+        callbackMemberTypes = [t for t in memberTypes if t.isCallback() or t.isCallbackInterface()]
         if len(callbackMemberTypes) > 0:
             assert len(callbackMemberTypes) == 1
             memberType = callbackMemberTypes[0]
@@ -5048,7 +5047,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             callbackObject = None
 
-        dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
+        dictionaryMemberTypes = [t for t in memberTypes if t.isDictionary()]
         if len(dictionaryMemberTypes) > 0:
             assert len(dictionaryMemberTypes) == 1
             name = getUnionMemberName(dictionaryMemberTypes[0])
@@ -5059,7 +5058,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             setDictionary = None
 
-        recordMemberTypes = filter(lambda t: t.isRecord(), memberTypes)
+        recordMemberTypes = [t for t in memberTypes if t.isRecord()]
         if len(recordMemberTypes) > 0:
             assert len(recordMemberTypes) == 1
             name = getUnionMemberName(recordMemberTypes[0])
@@ -5070,7 +5069,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
         else:
             recordObject = None
 
-        objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
+        objectMemberTypes = [t for t in memberTypes if t.isObject()]
         if len(objectMemberTypes) > 0:
             assert len(objectMemberTypes) == 1
             # Very important to NOT construct a temporary Rooted here, since the
@@ -5135,9 +5134,9 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
                 return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, tryNext)) || !tryNext;\n"
                                  "break;\n" % (unionArgumentObj, name))
             other = CGList([])
-            stringConversion = map(getStringOrPrimitiveConversion, stringTypes)
-            numericConversion = map(getStringOrPrimitiveConversion, numericTypes)
-            booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes)
+            stringConversion = list(map(getStringOrPrimitiveConversion, stringTypes))
+            numericConversion = list(map(getStringOrPrimitiveConversion, numericTypes))
+            booleanConversion = list(map(getStringOrPrimitiveConversion, booleanTypes))
             if stringConversion:
                 if booleanConversion:
                     other.append(CGIfWrapper(booleanConversion[0],
@@ -7744,7 +7743,7 @@ class CGPerSignatureCall(CGThing):
         }
         try:
             wrapCode += wrapForType(self.returnType, self.descriptor, resultTemplateValues)
-        except MethodNotNewObjectError, err:
+        except MethodNotNewObjectError as err:
             assert not returnsNewObject
             raise TypeError("%s being returned from non-NewObject method or property %s.%s" %
                             (err.typename,
@@ -8255,7 +8254,7 @@ class CGMethodCall(CGThing):
             # a string overload, then boolean and numeric are conditional, and
             # if not then boolean is conditional if we have a numeric overload.
             def findUniqueSignature(filterLambda):
-                sigs = filter(filterLambda, possibleSignatures)
+                sigs = list(filter(filterLambda, possibleSignatures))
                 assert len(sigs) < 2
                 if len(sigs) > 0:
                     return sigs[0]
@@ -9737,7 +9736,7 @@ class CGEnum(CGThing):
         return self.enum.identifier.name + "Values"
 
     def nEnumStrings(self):
-        return len(self.enum.values()) + 1
+        return len(list(self.enum.values())) + 1
 
     def declare(self):
         decl = fill(
@@ -9748,7 +9747,7 @@ class CGEnum(CGThing):
             };
             """,
             name=self.enum.identifier.name,
-            enums=",\n".join(map(getEnumValueName, self.enum.values())) + ",\n")
+            enums=",\n".join(map(getEnumValueName, list(self.enum.values()))) + ",\n")
         strings = CGNamespace(self.stringsNamespace(),
                               CGGeneric(declare="extern const EnumEntry %s[%d];\n"
                                         % (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings())))
@@ -13659,7 +13658,7 @@ class ForwardDeclarationBuilder:
         if self.decls:
             decls.append(CGList([CGClassForwardDeclare(cname, isStruct)
                                  for cname, isStruct in sorted(self.decls)]))
-        for namespace, child in sorted(self.children.iteritems()):
+        for namespace, child in sorted(self.children.items()):
             decls.append(CGNamespace(namespace, child._build(atTopLevel=False), declareOnly=True))
 
         cg = CGList(decls, "\n")
@@ -14009,10 +14008,10 @@ class CGBindingRoot(CGThing):
 
         # Add header includes.
         bindingHeaders = [header
-                          for header, include in bindingHeaders.iteritems()
+                          for header, include in bindingHeaders.items()
                           if include]
         bindingDeclareHeaders = [header
-                                 for header, include in bindingDeclareHeaders.iteritems()
+                                 for header, include in bindingDeclareHeaders.items()
                                  if include]
 
         curr = CGHeaders(descriptors,
@@ -14620,7 +14619,7 @@ class CGBindingImplClass(CGClass):
                                (returnType, args),
                                descriptor.getExtendedAttributes(op)))
         # Sort things by name so we get stable ordering in the output.
-        ops = descriptor.operations.items()
+        ops = list(descriptor.operations.items())
         ops.sort(key=lambda x: x[0])
         for name, op in ops:
             appendSpecialOperation(name, op)
@@ -16970,7 +16969,7 @@ class GlobalGenRoots():
     @staticmethod
     def UnionConversions(config):
         unionTypes = []
-        for l in config.unionsPerFilename.itervalues():
+        for l in config.unionsPerFilename.values():
             unionTypes.extend(l)
         unionTypes.sort(key=lambda u: u.name)
         headers, unions = UnionConversions(unionTypes,
@@ -17087,7 +17086,7 @@ class CGEventMethod(CGNativeMember):
                 # -3 on the left to ignore the type, bubbles, and cancelable parameters
                 # -1 on the right to ignore the .trusted property which bleeds through
                 # here because it is [Unforgeable].
-                len(signature[1]) - 3 == len(filter(lambda x: x.isAttr(), iface.members)) - 1):
+                len(signature[1]) - 3 == len([x for x in iface.members if x.isAttr()]) - 1):
                 allowed = True
                 self.isInit = True
 
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index 2669e3e4cd..20a93dffc6 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -28,7 +28,7 @@ class Configuration(DescriptorProvider):
 
         # Read the configuration file.
         glbl = {}
-        execfile(filename, glbl)
+        exec(compile(open(filename, "rb").read(), filename, 'exec'), glbl)
         config = glbl['DOMInterfaces']
 
         # Build descriptors for all the interfaces we have in the parse data.
@@ -87,7 +87,7 @@ class Configuration(DescriptorProvider):
             self.descriptorsByName[desc.interface.identifier.name] = desc
 
         # Keep the descriptor list sorted for determinism.
-        self.descriptors.sort(lambda x, y: cmp(x.name, y.name))
+        self.descriptors.sort(key=lambda x: x.name)
 
 
         self.descriptorsByFile = {}
@@ -149,8 +149,7 @@ class Configuration(DescriptorProvider):
                                 # unions for the file where we previously found
                                 # them.
                                 unionsForFilename = self.unionsPerFilename[f]
-                                unionsForFilename = filter(lambda u: u.name != t.name,
-                                                           unionsForFilename)
+                                unionsForFilename = [u for u in unionsForFilename if u.name != t.name]
                                 if len(unionsForFilename) == 0:
                                     del self.unionsPerFilename[f]
                                 else:
@@ -170,7 +169,7 @@ class Configuration(DescriptorProvider):
         # Collect up our filters, because we may have a webIDLFile filter that
         # we always want to apply first.
         tofilter = []
-        for key, val in filters.iteritems():
+        for key, val in filters.items():
             if key == 'webIDLFile':
                 # Special-case this part to make it fast, since most of our
                 # getDescriptors calls are conditioned on a webIDLFile.  We may
@@ -210,17 +209,17 @@ class Configuration(DescriptorProvider):
                 getter = (lambda attrName: lambda x: getattr(x, attrName))(key)
             tofilter.append((getter, val))
         for f in tofilter:
-            curr = filter(lambda x: f[0](x) == f[1], curr)
+            curr = [x for x in curr if f[0](x) == f[1]]
         return curr
 
     def getEnums(self, webIDLFile):
-        return filter(lambda e: e.filename() == webIDLFile, self.enums)
+        return [e for e in self.enums if e.filename() == webIDLFile]
 
     def getDictionaries(self, webIDLFile):
-        return filter(lambda d: d.filename() == webIDLFile, self.dictionaries)
+        return [d for d in self.dictionaries if d.filename() == webIDLFile]
 
     def getCallbacks(self, webIDLFile):
-        return filter(lambda c: c.filename() == webIDLFile, self.callbacks)
+        return [c for c in self.callbacks if c.filename() == webIDLFile]
 
     def getDescriptor(self, interfaceName):
         """
@@ -491,7 +490,7 @@ class Descriptor(DescriptorProvider):
                 if config == '*':
                     iface = self.interface
                     while iface:
-                        add('all', map(lambda m: m.name, iface.members), attribute)
+                        add('all', [m.name for m in iface.members], attribute)
                         iface = iface.parent
                 else:
                     add('all', [config], attribute)
@@ -543,7 +542,7 @@ class Descriptor(DescriptorProvider):
 
     @property
     def prototypeNameChain(self):
-        return map(lambda p: self.getDescriptor(p).name, self.prototypeChain)
+        return [self.getDescriptor(p).name for p in self.prototypeChain]
 
     @property
     def parentPrototypeName(self):
diff --git a/dom/bindings/GenerateCSS2PropertiesWebIDL.py b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
index b1f2a6016d..5341d05780 100644
--- a/dom/bindings/GenerateCSS2PropertiesWebIDL.py
+++ b/dom/bindings/GenerateCSS2PropertiesWebIDL.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import sys
 import string
 import argparse
diff --git a/dom/bindings/mozwebidlcodegen/__init__.py b/dom/bindings/mozwebidlcodegen/__init__.py
index 93b33012a7..928f194566 100644
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -7,6 +7,7 @@
 
 from __future__ import unicode_literals
 
+from __future__ import print_function
 import errno
 import hashlib
 import json
@@ -270,7 +271,7 @@ class WebIDLCodegenManager(LoggingMixin):
         # Generate bindings from .webidl files.
         for filename in sorted(changed_inputs):
             basename = mozpath.basename(filename)
-            print basename
+            print(basename)
             sys.stdout.flush()
             result.inputs.add(filename)
             written, deps = self._generate_build_files_for_webidl(filename)
@@ -296,7 +297,7 @@ class WebIDLCodegenManager(LoggingMixin):
         if self._make_deps_path:
             mk = Makefile()
             codegen_rule = mk.create_rule([self._make_deps_target])
-            codegen_rule.add_dependencies(global_hashes.keys())
+            codegen_rule.add_dependencies(list(global_hashes.keys()))
             codegen_rule.add_dependencies(self._input_paths)
 
             with FileAvoidWrite(self._make_deps_path) as fh:
@@ -314,7 +315,7 @@ class WebIDLCodegenManager(LoggingMixin):
 
         example_paths = self._example_paths(interface)
         for path in example_paths:
-            print "Generating %s" % path
+            print("Generating %s" % path)
 
         return self._maybe_write_codegen(root, *example_paths)
 
@@ -331,9 +332,9 @@ class WebIDLCodegenManager(LoggingMixin):
 
         for path in sorted(self._input_paths):
             with open(path, 'rb') as fh:
-                data = fh.read()
-                hashes[path] = hashlib.sha1(data).hexdigest()
-                parser.parse(data, path)
+                raw = fh.read()
+                hashes[path] = hashlib.sha1(raw).hexdigest()
+                parser.parse(raw.decode('utf-8'), path)
 
         self._parser_results = parser.finish()
         self._config = Configuration(self._config_path, self._parser_results,
@@ -519,7 +520,7 @@ class WebIDLCodegenManager(LoggingMixin):
         return False, current_hashes
 
     def _save_state(self):
-        with open(self._state_path, 'wb') as fh:
+        with open(self._state_path, 'w') as fh:
             self._state.dump(fh)
 
     def _maybe_write_codegen(self, obj, declare_path, define_path, result=None):
diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py
index 5c6b6eed32..7429ff073b 100644
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -4,6 +4,7 @@
 
 """ A WebIDL parser. """
 
+from __future__ import print_function
 from ply import lex, yacc
 import re
 import os
@@ -60,9 +61,7 @@ def enum(*names, **kw):
         base = object
         start = 0
 
-    class Foo(base):
-        __metaclass__ = M_add_class_attribs(names, start)
-
+    class Foo(base, metaclass=M_add_class_attribs(names, start)):
         def __setattr__(self, name, value):  # this makes it read-only
             raise NotImplementedError
     return Foo()
@@ -93,6 +92,9 @@ class Location(object):
         return (self._lexpos == other._lexpos and
                 self._file == other._file)
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def filename(self):
         return self._file
 
@@ -132,6 +134,9 @@ class BuiltinLocation(object):
         return (isinstance(other, BuiltinLocation) and
                 self.msg == other.msg)
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def filename(self):
         return '<builtin>'
 
@@ -962,7 +967,6 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
         # self.members.  Sort our consequential interfaces by name
         # just so we have a consistent order.
         for iface in sorted(self.getConsequentialInterfaces(),
-                            cmp=cmp,
                             key=lambda x: x.identifier.name):
             # Flag the interface as being someone's consequential interface
             iface.setIsConsequentialInterfaceOf(self)
@@ -1515,7 +1519,7 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
         assert len(naviProp) == 1
         assert isinstance(naviProp, list)
         assert len(naviProp[0]) != 0
-        conditionExtendedAttributes = self._extendedAttrDict.viewkeys() & IDLInterfaceOrNamespace.conditionExtendedAttributes
+        conditionExtendedAttributes = self._extendedAttrDict.keys() & IDLInterfaceOrNamespace.conditionExtendedAttributes
         attr = IDLAttribute(self.location,
                             IDLUnresolvedIdentifier(BuiltinLocation("<auto-generated-identifier>"), naviProp[0]),
                             IDLUnresolvedType(self.location, IDLUnresolvedIdentifier(self.location, self.identifier.name)),
@@ -1841,7 +1845,7 @@ class IDLDictionary(IDLObjectWithScope):
                 assert member.type.isComplete()
 
         # Members of a dictionary are sorted in lexicographic order
-        self.members.sort(cmp=cmp, key=lambda x: x.identifier.name)
+        self.members.sort(key=lambda x: x.identifier.name)
 
         inheritedMembers = []
         ancestor = self.parent
@@ -2012,6 +2016,9 @@ class IDLType(IDLObject):
     def __eq__(self, other):
         return other and self.builtin == other.builtin and self.name == other.name
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __ne__(self, other):
         return not self == other
 
@@ -2174,7 +2181,7 @@ class IDLUnresolvedType(IDLType):
 
         assert obj
         if obj.isType():
-            print obj
+            print(obj)
         assert not obj.isType()
         if obj.isTypedef():
             assert self.name.name == obj.identifier.name
@@ -2230,6 +2237,9 @@ class IDLNullableType(IDLParameterizedType):
     def __eq__(self, other):
         return isinstance(other, IDLNullableType) and self.inner == other.inner
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return self.inner.__str__() + "OrNull"
 
@@ -2360,6 +2370,9 @@ class IDLSequenceType(IDLParameterizedType):
     def __eq__(self, other):
         return isinstance(other, IDLSequenceType) and self.inner == other.inner
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return self.inner.__str__() + "Sequence"
 
@@ -2436,6 +2449,9 @@ class IDLRecordType(IDLParameterizedType):
     def __eq__(self, other):
         return isinstance(other, IDLRecordType) and self.inner == other.inner
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return self.keyType.__str__() + self.inner.__str__() + "Record"
 
@@ -2604,6 +2620,9 @@ class IDLTypedefType(IDLType):
     def __eq__(self, other):
         return isinstance(other, IDLTypedefType) and self.inner == other.inner
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return self.name
 
@@ -2729,6 +2748,9 @@ class IDLWrapperType(IDLType):
                 self._identifier == other._identifier and
                 self.builtin == other.builtin)
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return str(self.name) + " (Wrapper)"
 
@@ -2884,6 +2906,9 @@ class IDLPromiseType(IDLParameterizedType):
         return (isinstance(other, IDLPromiseType) and
                 self.promiseInnerType() == other.promiseInnerType())
 
+    def __hash__(self):
+        return object.__hash__(self)
+
     def __str__(self):
         return self.inner.__str__() + "Promise"
 
@@ -3328,7 +3353,7 @@ class IDLValue(IDLObject):
         elif self.type.isString() and type.isEnum():
             # Just keep our string, but make sure it's a valid value for this enum
             enum = type.unroll().inner
-            if self.value not in enum.values():
+            if self.value not in list(enum.values()):
                 raise WebIDLError("'%s' is not a valid default value for enum %s"
                                   % (self.value, enum.identifier.name),
                                   [location, enum.location])
@@ -3504,7 +3529,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
     def finish(self, scope):
         # We better be exposed _somewhere_.
         if (len(self._exposureGlobalNames) == 0):
-            print self.identifier.name
+            print(self.identifier.name)
         assert len(self._exposureGlobalNames) != 0
         IDLExposureMixins.finish(self, scope)
 
@@ -5261,7 +5286,7 @@ class Tokenizer(object):
         "ReadableStream": "READABLESTREAM",
         }
 
-    tokens.extend(keywords.values())
+    tokens.extend(list(keywords.values()))
 
     def t_error(self, t):
         raise WebIDLError("Unrecognized Input",
@@ -5417,7 +5442,7 @@ class Parser(Tokenizer):
                                       [location, existingObj.location])
                 existingObj.setNonPartial(*nonPartialArgs)
                 return existingObj
-        except Exception, ex:
+        except Exception as ex:
             if isinstance(ex, WebIDLError):
                 raise ex
             pass
@@ -5455,7 +5480,7 @@ class Parser(Tokenizer):
                                       "%s and %s" % (identifier.name, p[0]),
                                       [location, p[0].location])
                 return
-        except Exception, ex:
+        except Exception as ex:
             if isinstance(ex, WebIDLError):
                 raise ex
             pass
@@ -5518,7 +5543,7 @@ class Parser(Tokenizer):
                                       "non-%s object" %
                                       (prettyname, prettyname),
                                       [location, nonPartialObject.location])
-        except Exception, ex:
+        except Exception as ex:
             if isinstance(ex, WebIDLError):
                 raise ex
             pass
@@ -6820,7 +6845,7 @@ class Parser(Tokenizer):
         assert isinstance(scope, IDLScope)
 
         # xrange omits the last value.
-        for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
+        for x in range(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1):
             builtin = BuiltinTypes[x]
             name = builtin.name
             typedef = IDLTypedef(BuiltinLocation("<builtin type>"), scope, builtin, name)
@@ -6961,14 +6986,14 @@ def main():
             f = open(fullPath, 'rb')
             lines = f.readlines()
             f.close()
-            print fullPath
+            print(fullPath)
             parser.parse(''.join(lines), fullPath)
         parser.finish()
-    except WebIDLError, e:
+    except WebIDLError as e:
         if options.verbose_errors:
             traceback.print_exc()
         else:
-            print e
+            print(e)
 
 if __name__ == '__main__':
     main()
diff --git a/dom/bindings/parser/runtests.py b/dom/bindings/parser/runtests.py
index 33bb59f8ab..3947ede222 100644
--- a/dom/bindings/parser/runtests.py
+++ b/dom/bindings/parser/runtests.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os, sys
 import glob
 import argparse
@@ -22,22 +23,22 @@ class TestHarness(object):
 
     def finish(self):
         if self.verbose or self.printed_intro:
-            print "Finished test %s" % self.test
+            print("Finished test %s" % self.test)
 
     def maybe_print_intro(self):
         if not self.printed_intro:
-            print "Starting test %s" % self.test
+            print("Starting test %s" % self.test)
             self.printed_intro = True
 
     def test_pass(self, msg):
         self.passed += 1
         if self.verbose:
-            print "TEST-PASS | %s" % msg
+            print("TEST-PASS | %s" % msg)
 
     def test_fail(self, msg):
         self.maybe_print_intro()
         self.failures.append(msg)
-        print "TEST-UNEXPECTED-FAIL | %s" % msg
+        print("TEST-UNEXPECTED-FAIL | %s" % msg)
 
     def ok(self, condition, msg):
         if condition:
@@ -68,7 +69,7 @@ def run_tests(tests, verbose):
         harness.start()
         try:
             _test.WebIDLTest.__call__(WebIDL.Parser(), harness)
-        except Exception, ex:
+        except Exception as ex:
             harness.test_fail("Unhandled exception in test %s: %s" %
                               (testpath, ex))
             traceback.print_exc()
@@ -79,15 +80,15 @@ def run_tests(tests, verbose):
             failed_tests.append((test, harness.failures))
 
     if verbose or failed_tests:
-        print
-        print 'Result summary:'
-        print 'Successful: %d' % all_passed
-        print 'Unexpected: %d' % \
-                sum(len(failures) for _, failures in failed_tests)
+        print()
+        print('Result summary:')
+        print('Successful: %d' % all_passed)
+        print('Unexpected: %d' % \
+                sum(len(failures) for _, failures in failed_tests))
         for test, failures in failed_tests:
-            print '%s:' % test
+            print('%s:' % test)
             for failure in failures:
-                print 'TEST-UNEXPECTED-FAIL | %s' % failure
+                print('TEST-UNEXPECTED-FAIL | %s' % failure)
 
 def get_parser():
     usage = """%(prog)s [OPTIONS] [TESTS]
diff --git a/dom/bindings/parser/tests/test_attr.py b/dom/bindings/parser/tests/test_attr.py
index ad7aabc191..35f680aaa8 100644
--- a/dom/bindings/parser/tests/test_attr.py
+++ b/dom/bindings/parser/tests/test_attr.py
@@ -133,7 +133,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should not allow [SetterThrows] on readonly attributes")
 
@@ -146,7 +146,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should spell [Throws] correctly")
 
@@ -159,7 +159,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should not allow [SameObject] on attributes not of interface type")
 
@@ -172,6 +172,6 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(not threw, "Should allow [SameObject] on attributes of interface type")
diff --git a/dom/bindings/parser/tests/test_cereactions.py b/dom/bindings/parser/tests/test_cereactions.py
index 2f9397d903..d7ef94b079 100644
--- a/dom/bindings/parser/tests/test_cereactions.py
+++ b/dom/bindings/parser/tests/test_cereactions.py
@@ -38,7 +38,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, e:
+    except Exception as e:
         harness.ok(False, "Shouldn't have thrown for [CEReactions] used on writable attribute. %s" % e)
         threw = True
 
@@ -52,7 +52,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, e:
+    except Exception as e:
         harness.ok(False, "Shouldn't have thrown for [CEReactions] used on regular operations. %s" % e)
         threw = True
 
diff --git a/dom/bindings/parser/tests/test_conditional_dictionary_member.py b/dom/bindings/parser/tests/test_conditional_dictionary_member.py
index 433b7e501a..066300e8bb 100644
--- a/dom/bindings/parser/tests/test_conditional_dictionary_member.py
+++ b/dom/bindings/parser/tests/test_conditional_dictionary_member.py
@@ -44,7 +44,7 @@ def WebIDLTest(parser, harness):
         };
       """)
       results = parser.finish()
-    except Exception, exception:
+    except Exception as exception:
         pass
 
     harness.ok(exception, "Should have thrown.")
@@ -70,7 +70,7 @@ def WebIDLTest(parser, harness):
         };
       """)
       results = parser.finish()
-    except Exception, exception:
+    except Exception as exception:
         pass
 
     harness.ok(exception, "Should have thrown (2).")
@@ -100,7 +100,7 @@ def WebIDLTest(parser, harness):
         };
       """)
       results = parser.finish()
-    except Exception, exception:
+    except Exception as exception:
         pass
 
     harness.ok(exception, "Should have thrown (3).")
diff --git a/dom/bindings/parser/tests/test_constructor.py b/dom/bindings/parser/tests/test_constructor.py
index fb651c08d2..3dad20c8fb 100644
--- a/dom/bindings/parser/tests/test_constructor.py
+++ b/dom/bindings/parser/tests/test_constructor.py
@@ -32,7 +32,7 @@ def WebIDLTest(parser, harness):
         harness.check(method.isHTMLConstructor(), htmlConstructor, "Method has the correct htmlConstructor value")
         harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
 
-        sigpairs = zip(method.signatures(), signatures)
+        sigpairs = list(zip(method.signatures(), signatures))
         for (gotSignature, expectedSignature) in sigpairs:
             (gotRetType, gotArgs) = gotSignature
             (expectedRetType, expectedArgs) = expectedSignature
diff --git a/dom/bindings/parser/tests/test_deduplicate.py b/dom/bindings/parser/tests/test_deduplicate.py
index 6249d36fb8..3cc1ffecf6 100644
--- a/dom/bindings/parser/tests/test_deduplicate.py
+++ b/dom/bindings/parser/tests/test_deduplicate.py
@@ -11,5 +11,5 @@ def WebIDLTest(parser, harness):
 
     # There should be no duplicate interfaces in the result.
     expectedNames = sorted(['Foo', 'Bar'])
-    actualNames = sorted(map(lambda iface: iface.identifier.name, results))
+    actualNames = sorted([iface.identifier.name for iface in results])
     harness.check(actualNames, expectedNames, "Parser shouldn't output duplicate names.")
diff --git a/dom/bindings/parser/tests/test_empty_sequence_default_value.py b/dom/bindings/parser/tests/test_empty_sequence_default_value.py
index 350ae72f02..a713266c88 100644
--- a/dom/bindings/parser/tests/test_empty_sequence_default_value.py
+++ b/dom/bindings/parser/tests/test_empty_sequence_default_value.py
@@ -10,7 +10,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Constant cannot have [] as a default value")
diff --git a/dom/bindings/parser/tests/test_enum.py b/dom/bindings/parser/tests/test_enum.py
index 8622893918..a647fb83c5 100644
--- a/dom/bindings/parser/tests/test_enum.py
+++ b/dom/bindings/parser/tests/test_enum.py
@@ -26,7 +26,7 @@ def WebIDLTest(parser, harness):
     enum = results[0]
     harness.check(enum.identifier.QName(), "::TestEnum", "Enum has the right QName")
     harness.check(enum.identifier.name, "TestEnum", "Enum has the right name")
-    harness.check(enum.values(), ["", "foo", "bar"], "Enum has the right values")
+    harness.check(list(enum.values()), ["", "foo", "bar"], "Enum has the right values")
 
     iface = results[1]
 
diff --git a/dom/bindings/parser/tests/test_error_colno.py b/dom/bindings/parser/tests/test_error_colno.py
index ca0674aec0..7afd15513c 100644
--- a/dom/bindings/parser/tests/test_error_colno.py
+++ b/dom/bindings/parser/tests/test_error_colno.py
@@ -8,7 +8,7 @@ def WebIDLTest(parser, harness):
     try:
         parser.parse(input)
         results = parser.finish()
-    except WebIDL.WebIDLError, e:
+    except WebIDL.WebIDLError as e:
         threw = True
         lines = str(e).split('\n')
 
diff --git a/dom/bindings/parser/tests/test_error_lineno.py b/dom/bindings/parser/tests/test_error_lineno.py
index f11222e7a4..70bb188368 100644
--- a/dom/bindings/parser/tests/test_error_lineno.py
+++ b/dom/bindings/parser/tests/test_error_lineno.py
@@ -14,7 +14,7 @@ interface ?"""
     try:
         parser.parse(input)
         results = parser.finish()
-    except WebIDL.WebIDLError, e:
+    except WebIDL.WebIDLError as e:
         threw = True
         lines = str(e).split('\n')
 
diff --git a/dom/bindings/parser/tests/test_exposed_extended_attribute.py b/dom/bindings/parser/tests/test_exposed_extended_attribute.py
index 48957098bf..a6c04e30ca 100644
--- a/dom/bindings/parser/tests/test_exposed_extended_attribute.py
+++ b/dom/bindings/parser/tests/test_exposed_extended_attribute.py
@@ -124,7 +124,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on invalid Exposed value on interface.")
@@ -140,7 +140,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on invalid Exposed value on attribute.")
@@ -156,7 +156,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on invalid Exposed value on operation.")
@@ -172,7 +172,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on invalid Exposed value on constant.")
@@ -192,7 +192,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on member exposed where its interface is not.")
@@ -216,7 +216,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown on LHS of implements being exposed where RHS is not.")
diff --git a/dom/bindings/parser/tests/test_float_types.py b/dom/bindings/parser/tests/test_float_types.py
index 718f09c114..b7325cf9d2 100644
--- a/dom/bindings/parser/tests/test_float_types.py
+++ b/dom/bindings/parser/tests/test_float_types.py
@@ -68,7 +68,7 @@ def WebIDLTest(parser, harness):
               long m(float arg);
             };
         """)
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "[LenientFloat] only allowed on void methods")
 
@@ -81,7 +81,7 @@ def WebIDLTest(parser, harness):
               void m(unrestricted float arg);
             };
         """)
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args")
 
@@ -94,7 +94,7 @@ def WebIDLTest(parser, harness):
               void m(sequence<unrestricted float> arg);
             };
         """)
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (2)")
 
@@ -107,7 +107,7 @@ def WebIDLTest(parser, harness):
               void m((unrestricted float or FloatTypes) arg);
             };
         """)
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "[LenientFloat] only allowed on methods with unrestricted float args (3)")
 
@@ -120,6 +120,6 @@ def WebIDLTest(parser, harness):
               readonly attribute float foo;
             };
         """)
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "[LenientFloat] only allowed on writable attributes")
diff --git a/dom/bindings/parser/tests/test_identifier_conflict.py b/dom/bindings/parser/tests/test_identifier_conflict.py
index b510a30c04..0e9a6654aa 100644
--- a/dom/bindings/parser/tests/test_identifier_conflict.py
+++ b/dom/bindings/parser/tests/test_identifier_conflict.py
@@ -9,7 +9,7 @@ def WebIDLTest(parser, harness):
         """)
         results = parser.finish()
         harness.ok(False, "Should fail to parse")
-    except Exception, e:
+    except Exception as e:
         harness.ok("Name collision" in e.message,
                    "Should have name collision for interface")
 
@@ -21,7 +21,7 @@ def WebIDLTest(parser, harness):
         """)
         results = parser.finish()
         harness.ok(False, "Should fail to parse")
-    except Exception, e:
+    except Exception as e:
         harness.ok("Name collision" in e.message,
                    "Should have name collision for dictionary")
 
@@ -33,7 +33,7 @@ def WebIDLTest(parser, harness):
         """)
         results = parser.finish()
         harness.ok(False, "Should fail to parse")
-    except Exception, e:
+    except Exception as e:
         harness.ok("Multiple unresolvable definitions" in e.message,
                    "Should have name collision for dictionary")
 
diff --git a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
index ee5d870c20..72aa7617b8 100644
--- a/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
+++ b/dom/bindings/parser/tests/test_interface_maplikesetlikeiterable.py
@@ -37,10 +37,10 @@ def WebIDLTest(parser, harness):
             p.finish()
             harness.ok(False,
                        prefix + " - Interface passed when should've failed")
-        except WebIDL.WebIDLError, e:
+        except WebIDL.WebIDLError as e:
             harness.ok(True,
                        prefix + " - Interface failed as expected")
-        except Exception, e:
+        except Exception as e:
             harness.ok(False,
                        prefix + " - Interface failed but not as a WebIDLError exception: %s" % e)
 
diff --git a/dom/bindings/parser/tests/test_method.py b/dom/bindings/parser/tests/test_method.py
index cf7f1b40d7..2f5f4b0b2b 100644
--- a/dom/bindings/parser/tests/test_method.py
+++ b/dom/bindings/parser/tests/test_method.py
@@ -59,7 +59,7 @@ def WebIDLTest(parser, harness):
         harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value")
         harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures")
 
-        sigpairs = zip(method.signatures(), signatures)
+        sigpairs = list(zip(method.signatures(), signatures))
         for (gotSignature, expectedSignature) in sigpairs:
             (gotRetType, gotArgs) = gotSignature
             (expectedRetType, expectedArgs) = expectedSignature
@@ -121,7 +121,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(not threw, "Should allow integer to float type corecion")
 
@@ -134,7 +134,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should not allow [GetterThrows] on methods")
 
@@ -147,7 +147,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should not allow [SetterThrows] on methods")
 
@@ -160,7 +160,7 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should spell [Throws] correctly on methods")
 
@@ -173,6 +173,6 @@ def WebIDLTest(parser, harness):
           };
         """)
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should not allow __noSuchMethod__ methods")
diff --git a/dom/bindings/parser/tests/test_mozmap.py b/dom/bindings/parser/tests/test_mozmap.py
index 1a36fdd62c..fa852c02a0 100644
--- a/dom/bindings/parser/tests/test_mozmap.py
+++ b/dom/bindings/parser/tests/test_mozmap.py
@@ -33,7 +33,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
 
     harness.ok(threw, "Should have thrown.")
diff --git a/dom/bindings/parser/tests/test_namespace.py b/dom/bindings/parser/tests/test_namespace.py
index 74533a1770..62edb270c6 100644
--- a/dom/bindings/parser/tests/test_namespace.py
+++ b/dom/bindings/parser/tests/test_namespace.py
@@ -70,7 +70,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -85,7 +85,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -104,7 +104,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -123,7 +123,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -142,7 +142,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -161,7 +161,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -180,7 +180,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -199,7 +199,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -218,6 +218,6 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
diff --git a/dom/bindings/parser/tests/test_unenumerable_own_properties.py b/dom/bindings/parser/tests/test_unenumerable_own_properties.py
index d017d5ce09..d28cc1ec05 100644
--- a/dom/bindings/parser/tests/test_unenumerable_own_properties.py
+++ b/dom/bindings/parser/tests/test_unenumerable_own_properties.py
@@ -24,7 +24,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -39,7 +39,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
 
@@ -59,6 +59,6 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception, x:
+    except Exception as x:
         threw = True
     harness.ok(threw, "Should have thrown.")
diff --git a/dom/bindings/parser/tests/test_unforgeable.py b/dom/bindings/parser/tests/test_unforgeable.py
index 3787e8c6af..44a168670e 100644
--- a/dom/bindings/parser/tests/test_unforgeable.py
+++ b/dom/bindings/parser/tests/test_unforgeable.py
@@ -111,7 +111,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
     harness.ok(threw,
                "Should have thrown when shadowing unforgeable attribute on "
@@ -130,7 +130,7 @@ def WebIDLTest(parser, harness):
         """)
 
         results = parser.finish()
-    except Exception,x:
+    except Exception as x:
         threw = True
     harness.ok(threw,
                "Should have thrown when shadowing unforgeable operation on "
diff --git a/dom/bindings/parser/tests/test_union.py b/dom/bindings/parser/tests/test_union.py
index 9c4f2a56ab..aa538a97da 100644
--- a/dom/bindings/parser/tests/test_union.py
+++ b/dom/bindings/parser/tests/test_union.py
@@ -17,10 +17,10 @@ def combinations(iterable, r):
     n = len(pool)
     if r > n:
         return
-    indices = range(r)
+    indices = list(range(r))
     yield tuple(pool[i] for i in indices)
     while True:
-        for i in reversed(range(r)):
+        for i in reversed(list(range(r))):
             if indices[i] != i + n - r:
                 break
         else:
@@ -41,7 +41,7 @@ def combinations_with_replacement(iterable, r):
     indices = [0] * r
     yield tuple(pool[i] for i in indices)
     while True:
-        for i in reversed(range(r)):
+        for i in reversed(list(range(r))):
             if indices[i] != n - 1:
                 break
         else:
@@ -125,7 +125,7 @@ def WebIDLTest(parser, harness):
 
     # Create a list of tuples containing the name of the type as a string and
     # the parsed IDL type.
-    types = zip(types, (a.type for a in iface.members))
+    types = list(zip(types, (a.type for a in iface.members)))
 
     validUnionTypes = chain(unionTypes(combinations(types, 2), typesAreDistinguishable),
                             unionTypes(combinations(types, 3), typesAreDistinguishable))
diff --git a/dom/browser-element/mochitest/createNewTest.py b/dom/browser-element/mochitest/createNewTest.py
index 309ff95344..bd0f317280 100644
--- a/dom/browser-element/mochitest/createNewTest.py
+++ b/dom/browser-element/mochitest/createNewTest.py
@@ -2,7 +2,6 @@
 
 This script requires Python 2.7."""
 
-from __future__ import print_function
 
 import sys
 import os
@@ -59,9 +58,9 @@ def add_to_ini(filename, test, support_file=None):
     places in the file.
 
     """
-    lines_to_write = ['[{0}]'.format(test)]
+    lines_to_write = ['[{}]'.format(test)]
     if support_file:
-        lines_to_write += ['support-files = {0}'.format(support_file)]
+        lines_to_write += ['support-files = {}'.format(support_file)]
     lines_to_write += ['']
     with open(filename, 'a') as f:
         f.write('\n'.join(lines_to_write))
@@ -73,7 +72,7 @@ def add_to_ini(filename, test, support_file=None):
         return
 
     # Count the number of lines in the file
-    with open(filename, 'r') as f:
+    with open(filename) as f:
         num_lines = len(f.readlines())
 
     try:
@@ -81,7 +80,7 @@ def add_to_ini(filename, test, support_file=None):
                          '+%d' % (num_lines - len(lines_to_write) + 2),
                          filename])
     except Exception as e:
-        print_fill("Error opening $EDITOR: {0}.".format(e))
+        print_fill("Error opening $EDITOR: {}.".format(e))
         print()
         print_fill("""\
             Please open {filename} and move the filenames at the bottom of the
diff --git a/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py b/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
index 919ba23280..4f51f034e6 100644
--- a/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
+++ b/dom/canvas/test/webgl-mochitest/mochi-to-testcase.py
@@ -16,7 +16,7 @@ def ReadLocalFile(include):
 
     data = None
     try:
-        f = open(filePath, 'r')
+        f = open(filePath)
         data = f.read()
     except:
         pass
diff --git a/dom/media/test/external/external_media_harness/__init__.py b/dom/media/test/external/external_media_harness/__init__.py
index 906473f0bc..7ea101bbfe 100644
--- a/dom/media/test/external/external_media_harness/__init__.py
+++ b/dom/media/test/external/external_media_harness/__init__.py
@@ -2,4 +2,4 @@
 # 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 runtests import cli
+from .runtests import cli
diff --git a/dom/media/test/external/external_media_harness/runtests.py b/dom/media/test/external/external_media_harness/runtests.py
index 08d1a323b1..9762a16449 100644
--- a/dom/media/test/external/external_media_harness/runtests.py
+++ b/dom/media/test/external/external_media_harness/runtests.py
@@ -16,7 +16,7 @@ from marionette_harness import (
 from marionette_harness.runtests import MarionetteHarness, cli as mn_cli
 
 import external_media_tests
-from testcase import MediaTestCase
+from .testcase import MediaTestCase
 from external_media_tests.media_utils.video_puppeteer import debug_script
 
 
diff --git a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
index b904267dd4..475b4e7812 100644
--- a/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/video_puppeteer.py
@@ -2,6 +2,7 @@
 # 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 print_function
 from collections import namedtuple
 from time import clock, sleep
 
@@ -181,7 +182,7 @@ class VideoPuppeteer(object):
                 played_ranges.end(0) > 0.0
             )
         except Exception as e:
-            print ('Got exception {}'.format(e))
+            print(('Got exception {}'.format(e)))
             return False
 
     def playback_done(self):
@@ -408,7 +409,7 @@ class VideoPuppeteer(object):
         for field in self._last_seen_video_state._fields:
             # For compatibility with different test environments we force ascii
             field_ascii = (
-                unicode(getattr(self._last_seen_video_state, field))
+                str(getattr(self._last_seen_video_state, field))
                 .encode('ascii','replace'))
             messages += [('\t{}: {}'.format(field, field_ascii))]
         messages += '}'
diff --git a/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
index e42bbcc875..3ec9ec9208 100644
--- a/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
+++ b/dom/media/test/external/external_media_tests/media_utils/youtube_puppeteer.py
@@ -12,7 +12,7 @@ from marionette_driver import By, expected, Wait
 from marionette_driver.errors import TimeoutException, NoSuchElementException
 from marionette_harness import Marionette
 
-from video_puppeteer import VideoPuppeteer, VideoException
+from .video_puppeteer import VideoPuppeteer, VideoException
 from external_media_tests.utils import verbose_until
 
 
@@ -489,7 +489,7 @@ class YouTubePuppeteer(VideoPuppeteer):
         for field in self._last_seen_player_state._fields:
             # For compatibility with different test environments we force ascii
             field_ascii = (
-                unicode(getattr(self._last_seen_player_state, field))
+                str(getattr(self._last_seen_player_state, field))
                         .encode('ascii', 'replace'))
             messages += [('\t{}: {}'.format(field, field_ascii))]
         messages += '}'
diff --git a/dom/media/test/external/external_media_tests/playback/test_eme_playback.py b/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
index 9c7eb67258..373ede2462 100644
--- a/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
+++ b/dom/media/test/external/external_media_tests/playback/test_eme_playback.py
@@ -1,18 +1,18 @@
-# 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 external_media_harness.testcase import (
-    MediaTestCase,
-    VideoPlaybackTestsMixin,
-    EMESetupMixin
-)
-
-
-class TestEMEPlayback(MediaTestCase, VideoPlaybackTestsMixin, EMESetupMixin):
-
-    def setUp(self):
-        super(TestEMEPlayback, self).setUp()
-        self.check_eme_system()
-
-    # Tests are implemented in VideoPlaybackTestsMixin
+# 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 external_media_harness.testcase import (
+    MediaTestCase,
+    VideoPlaybackTestsMixin,
+    EMESetupMixin
+)
+
+
+class TestEMEPlayback(MediaTestCase, VideoPlaybackTestsMixin, EMESetupMixin):
+
+    def setUp(self):
+        super(TestEMEPlayback, self).setUp()
+        self.check_eme_system()
+
+    # Tests are implemented in VideoPlaybackTestsMixin
diff --git a/dom/media/test/external/mach_commands.py b/dom/media/test/external/mach_commands.py
index e309f3c55e..487a7d21fe 100644
--- a/dom/media/test/external/mach_commands.py
+++ b/dom/media/test/external/mach_commands.py
@@ -45,7 +45,7 @@ def run_external_media_test(tests, testtype=None, topsrcdir=None, **kwargs):
 
     args = Namespace(tests=tests)
 
-    for k, v in kwargs.iteritems():
+    for k, v in kwargs.items():
         setattr(args, k, v)
 
     parser.verify_usage(args)
diff --git a/dom/media/test/graph_latency.py b/dom/media/test/graph_latency.py
index 576f58d864..f0df270c35 100644
--- a/dom/media/test/graph_latency.py
+++ b/dom/media/test/graph_latency.py
@@ -7,6 +7,7 @@
 
 # needs matplotlib (sudo aptitude install python-matplotlib)
 
+from __future__ import print_function
 import matplotlib.pyplot as plt
 from matplotlib import rc
 import sys
@@ -22,10 +23,10 @@ def compute_sum(data):
     out = ([],[])
 
     for i in data:
-        if i[0] not in last_values.keys():
+        if i[0] not in list(last_values.keys()):
           last_values[i[0]] = 0
         last_values[i[0]] = float(i[3])
-        print last_values
+        print(last_values)
         out[0].append(i[2])
         out[1].append(sum(last_values.values()))
     return out
@@ -59,12 +60,12 @@ if len(sys.argv) == 3:
     name = sys.argv[1]
     channels = int(sys.argv[2])
 else:
-    print sys.argv[0] + "latency_log"
+    print(sys.argv[0] + "latency_log")
 
 try:
     f = open(sys.argv[1])
 except:
-    print "cannot open " + name
+    print("cannot open " + name)
 
 raw_lines = f.readlines()
 lines = clean_data(raw_lines)
@@ -76,7 +77,7 @@ for tupl in data:
     name = tupl[0]
     if tupl[1] != 0:
         name = name+tupl[1]
-    if name not in final_data.keys():
+    if name not in list(final_data.keys()):
         final_data[name] = ([], [])
 # sanity-check values
     if float(tupl[3]) < 10*1000:
diff --git a/dom/security/test/csp/file_websocket_self_wsh.py b/dom/security/test/csp/file_websocket_self_wsh.py
index 5fe508a910..0ae161bff1 100644
--- a/dom/security/test/csp/file_websocket_self_wsh.py
+++ b/dom/security/test/csp/file_websocket_self_wsh.py
@@ -1,7 +1,7 @@
-from mod_pywebsocket import msgutil
-
-def web_socket_do_extra_handshake(request):
-  pass
-
-def web_socket_transfer_data(request):
-  pass
+from mod_pywebsocket import msgutil
+
+def web_socket_do_extra_handshake(request):
+  pass
+
+def web_socket_transfer_data(request):
+  pass
diff --git a/gfx/angle/src/commit_id.py b/gfx/angle/src/commit_id.py
index bbdb810ce0..fcae35797c 100755
--- a/gfx/angle/src/commit_id.py
+++ b/gfx/angle/src/commit_id.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import subprocess as sp
 import sys
 import os
diff --git a/gfx/angle/src/common/Float16ToFloat32.py b/gfx/angle/src/common/Float16ToFloat32.py
index 7705f7b619..04af0dff3e 100755
--- a/gfx/angle/src/common/Float16ToFloat32.py
+++ b/gfx/angle/src/common/Float16ToFloat32.py
@@ -9,6 +9,7 @@
 
 #include "common/mathutil.h"
 
+from __future__ import print_function
 def convertMantissa(i):
     if i == 0:
         return 0
@@ -44,7 +45,7 @@ def convertOffset(i):
     else:
         return 1024
 
-print """//
+print("""//
 // Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
@@ -54,27 +55,27 @@ print """//
 
 namespace gl
 {
-"""
+""")
 
-print "const static unsigned g_mantissa[2048] = {"
+print("const static unsigned g_mantissa[2048] = {")
 for i in range(0, 2048):
-    print "    %#010x," % convertMantissa(i)
-print "};\n"
+    print("    %#010x," % convertMantissa(i))
+print("};\n")
 
-print "const static unsigned g_exponent[64] = {"
+print("const static unsigned g_exponent[64] = {")
 for i in range(0, 64):
-    print "    %#010x," % convertExponent(i)
-print "};\n"
+    print("    %#010x," % convertExponent(i))
+print("};\n")
 
-print "const static unsigned g_offset[64] = {"
+print("const static unsigned g_offset[64] = {")
 for i in range(0, 64):
-    print "    %#010x," % convertOffset(i)
-print "};\n"
+    print("    %#010x," % convertOffset(i))
+print("};\n")
 
-print """float float16ToFloat32(unsigned short h)
+print("""float float16ToFloat32(unsigned short h)
 {
     unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10];
     return bitCast<float>(i32);
 }
 }
-"""
+""")
diff --git a/gfx/angle/src/libANGLE/renderer/angle_format.py b/gfx/angle/src/libANGLE/renderer/angle_format.py
index e46bc7dba9..c0be62baec 100755
--- a/gfx/angle/src/libANGLE/renderer/angle_format.py
+++ b/gfx/angle/src/libANGLE/renderer/angle_format.py
@@ -39,7 +39,7 @@ def load_with_override(override_path):
     results = load_forward_table(map_path)
     overrides = load_json(override_path)
 
-    for k, v in overrides.iteritems():
+    for k, v in overrides.items():
         results[k] = v
 
     return results
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_dxgi_support_tables.py b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_dxgi_support_tables.py
index 21b22803b9..282dbf4496 100755
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_dxgi_support_tables.py
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_dxgi_support_tables.py
@@ -13,6 +13,7 @@
 #  11_0: https://msdn.microsoft.com/en-us/library/windows/desktop/ff471325.aspx
 #  11_1: https://msdn.microsoft.com/en-us/library/windows/desktop/hh404483.aspx
 
+from __future__ import print_function
 import sys
 import json
 
@@ -141,7 +142,7 @@ def do_format(format_data):
         'depthStencil': macro_prefix + 'DS'
     }
 
-    for format_name, format_support in sorted(format_data.iteritems()):
+    for format_name, format_support in sorted(format_data.items()):
 
         always_supported = set()
         never_supported = set()
@@ -152,7 +153,7 @@ def do_format(format_data):
         fl_10_0_check_10_1_supported = set()
         fl_10_0_check_11_0_supported = set()
 
-        for json_flag, support in format_support.iteritems():
+        for json_flag, support in format_support.items():
 
             d3d_flag = [json_flag_to_d3d[json_flag]]
 
@@ -182,7 +183,7 @@ def do_format(format_data):
             elif support == '11_0check':
                 fl_11_0_check.update(d3d_flag)
             else:
-                print("Data specification error: " + support)
+                print(("Data specification error: " + support))
                 sys.exit(1)
 
         for feature_level in ['10_0', '10_1', '11_0']:
diff --git a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py
index 981a77f51a..7cca2c22c2 100755
--- a/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py
+++ b/gfx/angle/src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py
@@ -158,8 +158,8 @@ def get_swizzle_format_id(internal_format, angle_format):
         raise ValueError('no bits information for determining swizzleformat for format: ' + internal_format)
 
     bits = angle_format['bits']
-    max_component_bits = max(bits.itervalues())
-    channels_different = not all([component_bits == bits.itervalues().next() for component_bits in bits.itervalues()])
+    max_component_bits = max(bits.values())
+    channels_different = not all([component_bits == next(bits.values()) for component_bits in bits.values()])
 
     # The format itself can be used for swizzles if it can be accessed as a render target and
     # sampled and the bit count for all 4 channels is the same.
@@ -261,7 +261,7 @@ def json_to_table_data(internal_format, format_name, prefix, json):
         "condition": prefix,
     }
 
-    for k, v in json.iteritems():
+    for k, v in json.items():
         parsed[k] = v
 
     # Derived values.
@@ -280,15 +280,15 @@ def parse_json_angle_format_case(format_name, angle_format, json_data):
     support_test = None
     fallback = None
 
-    for k, v in angle_format.iteritems():
+    for k, v in angle_format.items():
         if k == "FL10Plus":
             assert support_test is None
             support_test = "OnlyFL10Plus(deviceCaps)"
-            for k2, v2 in v.iteritems():
+            for k2, v2 in v.items():
                 supported_case[k2] = v2
         elif k == "FL9_3":
             split = True
-            for k2, v2 in v.iteritems():
+            for k2, v2 in v.items():
                 unsupported_case[k2] = v2
         elif k == "supportTest":
             assert support_test is None
@@ -312,7 +312,7 @@ def parse_json_angle_format_case(format_name, angle_format, json_data):
 def parse_json_into_switch_angle_format_string(json_map, json_data):
     table_data = ''
 
-    for internal_format, format_name in sorted(json_map.iteritems()):
+    for internal_format, format_name in sorted(json_map.items()):
 
         if format_name not in json_data:
             continue
diff --git a/gfx/angle/src/libANGLE/renderer/gen_angle_format_table.py b/gfx/angle/src/libANGLE/renderer/gen_angle_format_table.py
index 7356fc4149..d6a8357ee5 100755
--- a/gfx/angle/src/libANGLE/renderer/gen_angle_format_table.py
+++ b/gfx/angle/src/libANGLE/renderer/gen_angle_format_table.py
@@ -153,7 +153,7 @@ def get_component_type(format_id):
 
 def get_channel_tokens(format_id):
     r = re.compile(r'([ABDGLRS][\d]+)')
-    return filter(r.match, r.split(format_id))
+    return list(filter(r.match, r.split(format_id)))
 
 def get_channels(format_id):
     channels = ''
@@ -183,7 +183,7 @@ def json_to_table_data(format_id, json, angle_to_gl):
         "id": format_id,
     }
 
-    for k, v in json.iteritems():
+    for k, v in json.items():
         parsed[k] = v
 
     if "glInternalFormat" not in parsed:
@@ -227,7 +227,7 @@ def gen_enum_string(all_angle):
 gl_to_angle = angle_format.load_forward_table('angle_format_map.json')
 angle_to_gl = angle_format.load_inverse_table('angle_format_map.json')
 json_data = angle_format.load_json('angle_format_data.json')
-all_angle = angle_to_gl.keys()
+all_angle = list(angle_to_gl.keys())
 
 angle_format_cases = parse_json_into_angle_format_switch_string(
     all_angle, json_data, angle_to_gl)
diff --git a/gfx/angle/src/libANGLE/renderer/gen_load_functions_table.py b/gfx/angle/src/libANGLE/renderer/gen_load_functions_table.py
index eb3e4c5bf0..2ba474680a 100755
--- a/gfx/angle/src/libANGLE/renderer/gen_load_functions_table.py
+++ b/gfx/angle/src/libANGLE/renderer/gen_load_functions_table.py
@@ -107,7 +107,7 @@ def get_load_func(func_name, type_functions):
     snippet += "{\n"
     snippet += "    switch (type)\n"
     snippet += "    {\n"
-    for gl_type, load_function in sorted(type_functions.iteritems()):
+    for gl_type, load_function in sorted(type_functions.items()):
         snippet += "        case " + gl_type + ":\n"
         requiresConversion = str('LoadToNative<' not in load_function).lower()
         snippet += "            return LoadImageFunctionInfo(" + load_function + ", " + requiresConversion + ");\n"
@@ -127,13 +127,13 @@ def get_unknown_load_func(angle_to_type_map, internal_format):
 def parse_json(json_data):
     table_data = ''
     load_functions_data = ''
-    for internal_format, angle_to_type_map in sorted(json_data.iteritems()):
+    for internal_format, angle_to_type_map in sorted(json_data.items()):
 
         s = '        '
 
         table_data += s + 'case ' + internal_format + ':\n'
 
-        do_switch = len(angle_to_type_map) > 1 or angle_to_type_map.keys()[0] != angle_format_unknown
+        do_switch = len(angle_to_type_map) > 1 or list(angle_to_type_map.keys())[0] != angle_format_unknown
 
         if do_switch:
             table_data += s + '{\n'
@@ -142,7 +142,7 @@ def parse_json(json_data):
             table_data += s + '{\n'
             s += '    '
 
-        for angle_format, type_functions in sorted(angle_to_type_map.iteritems()):
+        for angle_format, type_functions in sorted(angle_to_type_map.items()):
 
             if angle_format == angle_format_unknown:
                 continue
@@ -154,7 +154,7 @@ def parse_json(json_data):
             table_data += s + '    return ' + func_name + ';\n'
 
             if angle_format_unknown in angle_to_type_map:
-                for gl_type, load_function in angle_to_type_map[angle_format_unknown].iteritems():
+                for gl_type, load_function in angle_to_type_map[angle_format_unknown].items():
                     if gl_type not in type_functions:
                         type_functions[gl_type] = load_function
 
diff --git a/gfx/gl/GLParseRegistryXML.py b/gfx/gl/GLParseRegistryXML.py
index 60daca6e56..0519cbfc0f 100755
--- a/gfx/gl/GLParseRegistryXML.py
+++ b/gfx/gl/GLParseRegistryXML.py
@@ -22,6 +22,7 @@
 ################################################################################
 
 # includes
+from __future__ import print_function
 import os
 import sys
 import xml.etree.ElementTree
@@ -38,7 +39,7 @@ class GLConstHeader:
     def write(self, arg):
         if isinstance(arg, list):
             self.f.write('\n'.join(arg) + '\n')
-        elif isinstance(arg, (int, long)):
+        elif isinstance(arg, int):
             self.f.write('\n' * arg)
         else:
             self.f.write(str(arg) + '\n')
@@ -137,7 +138,7 @@ class GLDatabase:
         xmlPath = getXMLDir() + path
 
         if not os.path.isfile(xmlPath):
-            print 'missing file "' + xmlPath + '"'
+            print('missing file "' + xmlPath + '"')
             return False
 
         tree = xml.etree.ElementTree.parse(xmlPath)
@@ -186,7 +187,7 @@ class GLDatabase:
             headerFile = GLConstHeader(f)
             headerFile.formatFileBegin()
 
-            constNames = self.consts.keys()
+            constNames = list(self.consts.keys())
             constNames.sort()
 
             for lib in GLDatabase.LIBS:
diff --git a/gfx/harfbuzz/src/check-c-linkage-decls.py b/gfx/harfbuzz/src/check-c-linkage-decls.py
index 3c206115a9..80395b38e6 100644
--- a/gfx/harfbuzz/src/check-c-linkage-decls.py
+++ b/gfx/harfbuzz/src/check-c-linkage-decls.py
@@ -1,36 +1,37 @@
-#!/usr/bin/env python3
-
-import sys, os
-
-srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
-base_srcdir = os.getenv ('base_srcdir', srcdir)
-
-os.chdir (srcdir)
-
-def removeprefix(s):
-	abs_path = os.path.join(base_srcdir, s)
-	return os.path.relpath(abs_path, srcdir)
-
-
-HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
-	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [
-    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
-] or [
-    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
-]
-stat = 0
-
-for x in HBHEADERS:
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	if ('HB_BEGIN_DECLS' not in content) or ('HB_END_DECLS' not in content):
-		print ('Ouch, file %s does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should' % x)
-		stat = 1
-
-for x in HBSOURCES:
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	if ('HB_BEGIN_DECLS' in content) or ('HB_END_DECLS' in content):
-		print ('Ouch, file %s has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn\'t' % x)
-		stat = 1
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os
+
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+	abs_path = os.path.join(base_srcdir, s)
+	return os.path.relpath(abs_path, srcdir)
+
+
+HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
+	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+stat = 0
+
+for x in HBHEADERS:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if ('HB_BEGIN_DECLS' not in content) or ('HB_END_DECLS' not in content):
+		print(('Ouch, file %s does not have HB_BEGIN_DECLS / HB_END_DECLS, but it should' % x))
+		stat = 1
+
+for x in HBSOURCES:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if ('HB_BEGIN_DECLS' in content) or ('HB_END_DECLS' in content):
+		print(('Ouch, file %s has HB_BEGIN_DECLS / HB_END_DECLS, but it shouldn\'t' % x))
+		stat = 1
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/check-externs.py b/gfx/harfbuzz/src/check-externs.py
index 3905cc4fc6..facf559670 100644
--- a/gfx/harfbuzz/src/check-externs.py
+++ b/gfx/harfbuzz/src/check-externs.py
@@ -1,20 +1,21 @@
-#!/usr/bin/env python3
-
-import sys, os, re
-
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
-
-HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
-	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-
-stat = 0
-
-print ('Checking that all public symbols are exported with HB_EXTERN')
-for x in HBHEADERS:
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	for s in re.findall (r'\n.+\nhb_.+\n', content):
-		if not s.startswith ('\nHB_EXTERN '):
-			print ('failure on:', s)
-			stat = 1
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, re
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
+	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
+
+stat = 0
+
+print ('Checking that all public symbols are exported with HB_EXTERN')
+for x in HBHEADERS:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	for s in re.findall (r'\n.+\nhb_.+\n', content):
+		if not s.startswith ('\nHB_EXTERN '):
+			print(('failure on:', s))
+			stat = 1
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/check-header-guards.py b/gfx/harfbuzz/src/check-header-guards.py
index ba7d42fbac..a3de9c5184 100644
--- a/gfx/harfbuzz/src/check-header-guards.py
+++ b/gfx/harfbuzz/src/check-header-guards.py
@@ -1,34 +1,35 @@
-#!/usr/bin/env python3
-
-import sys, os, re
-
-srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
-base_srcdir = os.getenv ('base_srcdir', srcdir)
-
-os.chdir (srcdir)
-
-def removeprefix(s):
-	abs_path = os.path.join(base_srcdir, s)
-	return os.path.relpath(abs_path, srcdir)
-
-
-HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
-	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-HBSOURCES = [
-    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
-] or [
-    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
-]
-
-
-stat = 0
-
-for x in HBHEADERS + HBSOURCES:
-	if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
-	tag = x.upper ().replace ('.', '_').replace ('-', '_').replace(os.path.sep, '_').replace('/', '_')
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	if len (re.findall (tag + r'\b', content)) != 3:
-		print ('Ouch, header file %s does not have correct preprocessor guards. Expected: %s' % (x, tag))
-		stat = 1
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, re
+
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+	abs_path = os.path.join(base_srcdir, s)
+	return os.path.relpath(abs_path, srcdir)
+
+
+HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
+	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
+
+stat = 0
+
+for x in HBHEADERS + HBSOURCES:
+	if not x.endswith ('h') or x == 'hb-gobject-structs.h': continue
+	tag = x.upper ().replace ('.', '_').replace ('-', '_').replace(os.path.sep, '_').replace('/', '_')
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if len (re.findall (tag + r'\b', content)) != 3:
+		print(('Ouch, header file %s does not have correct preprocessor guards. Expected: %s' % (x, tag)))
+		stat = 1
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/check-includes.py b/gfx/harfbuzz/src/check-includes.py
index 2cead7b3f9..829ac835eb 100644
--- a/gfx/harfbuzz/src/check-includes.py
+++ b/gfx/harfbuzz/src/check-includes.py
@@ -1,51 +1,52 @@
-#!/usr/bin/env python3
-
-import sys, os, re
-
-srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
-base_srcdir = os.getenv ('base_srcdir', srcdir)
-
-os.chdir (srcdir)
-
-def removeprefix(s):
-	abs_path = os.path.join(base_srcdir, s)
-	return os.path.relpath(abs_path, srcdir)
-
-HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
-	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
-
-HBSOURCES = [
-    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
-] or [
-    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
-]
-
-
-stat = 0
-
-print ('Checking that public header files #include "hb-common.h" or "hb.h" first (or none)')
-for x in HBHEADERS:
-	if x == 'hb.h' or x == 'hb-common.h': continue
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	first = re.findall (r'#.*include.*', content)[0]
-	if first not in ['#include "hb.h"', '#include "hb-common.h"']:
-		print ('failure on %s' % x)
-		stat = 1
-
-print ('Checking that source files #include a private header first (or none)')
-for x in HBSOURCES:
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	includes = re.findall (r'#.*include.*', content)
-	if includes:
-		if not len (re.findall (r'".*\.hh"', includes[0])):
-			print ('failure on %s' % x)
-			stat = 1
-
-print ('Checking that there is no #include <hb-*.h>')
-for x in HBHEADERS + HBSOURCES:
-	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
-	if re.findall ('#.*include.*<.*hb', content):
-		print ('failure on %s' % x)
-		stat = 1
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, re
+
+srcdir = os.getenv ('srcdir', os.path.dirname (__file__))
+base_srcdir = os.getenv ('base_srcdir', srcdir)
+
+os.chdir (srcdir)
+
+def removeprefix(s):
+	abs_path = os.path.join(base_srcdir, s)
+	return os.path.relpath(abs_path, srcdir)
+
+HBHEADERS = [os.path.basename (x) for x in os.getenv ('HBHEADERS', '').split ()] or \
+	[x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith ('.h')]
+
+HBSOURCES = [
+    removeprefix(x) for x in os.getenv ('HBSOURCES', '').split ()
+] or [
+    x for x in os.listdir ('.') if x.startswith ('hb') and x.endswith (('.cc', '.hh'))
+]
+
+
+stat = 0
+
+print ('Checking that public header files #include "hb-common.h" or "hb.h" first (or none)')
+for x in HBHEADERS:
+	if x == 'hb.h' or x == 'hb-common.h': continue
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	first = re.findall (r'#.*include.*', content)[0]
+	if first not in ['#include "hb.h"', '#include "hb-common.h"']:
+		print(('failure on %s' % x))
+		stat = 1
+
+print ('Checking that source files #include a private header first (or none)')
+for x in HBSOURCES:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	includes = re.findall (r'#.*include.*', content)
+	if includes:
+		if not len (re.findall (r'".*\.hh"', includes[0])):
+			print(('failure on %s' % x))
+			stat = 1
+
+print ('Checking that there is no #include <hb-*.h>')
+for x in HBHEADERS + HBSOURCES:
+	with open (x, 'r', encoding='utf-8') as f: content = f.read ()
+	if re.findall ('#.*include.*<.*hb', content):
+		print(('failure on %s' % x))
+		stat = 1
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/check-libstdc++.py b/gfx/harfbuzz/src/check-libstdc++.py
index 4cfab52d4b..ffa11d245e 100644
--- a/gfx/harfbuzz/src/check-libstdc++.py
+++ b/gfx/harfbuzz/src/check-libstdc++.py
@@ -1,39 +1,40 @@
-#!/usr/bin/env python3
-
-import sys, os, shutil, subprocess
-
-os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
-
-libs = os.getenv ('libs', '.libs')
-
-ldd = os.getenv ('LDD', shutil.which ('ldd'))
-if not ldd:
-	otool = os.getenv ('OTOOL', shutil.which ('otool'))
-	if otool:
-		ldd = otool + ' -L'
-	else:
-		print ('check-libstdc++.py: \'ldd\' not found; skipping test')
-		sys.exit (77)
-
-stat = 0
-tested = False
-
-# harfbuzz-icu links to libstdc++ because icu does.
-for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']:
-	for suffix in ['so', 'dylib']:
-		so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
-		if not os.path.exists (so): continue
-
-		print ('Checking that we are not linking to libstdc++ or libc++ in %s' % so)
-		ldd_result = subprocess.check_output (ldd.split() + [so])
-		if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
-			print ('Ouch, %s is linked to libstdc++ or libc++' % so)
-			stat = 1
-
-		tested = True
-
-if not tested:
-	print ('check-libstdc++.py: libharfbuzz shared library not found; skipping test')
-	sys.exit (77)
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, shutil, subprocess
+
+os.chdir (os.getenv ('srcdir', os.path.dirname (__file__)))
+
+libs = os.getenv ('libs', '.libs')
+
+ldd = os.getenv ('LDD', shutil.which ('ldd'))
+if not ldd:
+	otool = os.getenv ('OTOOL', shutil.which ('otool'))
+	if otool:
+		ldd = otool + ' -L'
+	else:
+		print ('check-libstdc++.py: \'ldd\' not found; skipping test')
+		sys.exit (77)
+
+stat = 0
+tested = False
+
+# harfbuzz-icu links to libstdc++ because icu does.
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']:
+	for suffix in ['so', 'dylib']:
+		so = os.path.join (libs, 'lib%s.%s' % (soname, suffix))
+		if not os.path.exists (so): continue
+
+		print(('Checking that we are not linking to libstdc++ or libc++ in %s' % so))
+		ldd_result = subprocess.check_output (ldd.split() + [so])
+		if (b'libstdc++' in ldd_result) or (b'libc++' in ldd_result):
+			print(('Ouch, %s is linked to libstdc++ or libc++' % so))
+			stat = 1
+
+		tested = True
+
+if not tested:
+	print ('check-libstdc++.py: libharfbuzz shared library not found; skipping test')
+	sys.exit (77)
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/check-static-inits.py b/gfx/harfbuzz/src/check-static-inits.py
index 7217f03934..4e5ab1bd86 100644
--- a/gfx/harfbuzz/src/check-static-inits.py
+++ b/gfx/harfbuzz/src/check-static-inits.py
@@ -1,51 +1,52 @@
-#!/usr/bin/env python3
-
-import sys, os, shutil, subprocess, glob, re
-
-builddir = os.getenv ('builddir', os.path.dirname (__file__))
-libs = os.getenv ('libs', '.libs')
-
-objdump = os.getenv ('OBJDUMP', shutil.which ('objdump'))
-if not objdump:
-	print ('check-static-inits.py: \'ldd\' not found; skipping test')
-	sys.exit (77)
-
-if sys.version_info < (3, 5):
-	print ('check-static-inits.py: needs python 3.5 for recursive support in glob')
-	sys.exit (77)
-
-OBJS = glob.glob (os.path.join (builddir, libs, '**', '*hb*.o'), recursive=True)
-if not OBJS:
-	print ('check-static-inits.py: object files not found; skipping test')
-	sys.exit (77)
-
-stat = 0
-tested = 0
-
-for obj in OBJS:
-	result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
-	if result.returncode:
-		if result.stderr.find (b'not recognized') != -1:
-			# https://github.com/harfbuzz/harfbuzz/issues/3019
-			print ('objdump %s returned "not recognized", skipping' % obj)
-			continue
-		print ('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8')))
-		stat = 2
-
-	result = result.stdout.decode ('utf-8')
-
-	# Checking that no object file has static initializers
-	for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
-		if not re.match (r'.*\b0+\b', l):
-			print ('Ouch, %s has static initializers/finalizers' % obj)
-			stat = 1
-
-	# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
-	if ('__cxa_' in result) and ('__ubsan_handle' not in result):
-		print ('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj)
-		stat = 1
-
-	tested += 1
-
-sys.exit (stat if tested else 77)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, shutil, subprocess, glob, re
+
+builddir = os.getenv ('builddir', os.path.dirname (__file__))
+libs = os.getenv ('libs', '.libs')
+
+objdump = os.getenv ('OBJDUMP', shutil.which ('objdump'))
+if not objdump:
+	print ('check-static-inits.py: \'ldd\' not found; skipping test')
+	sys.exit (77)
+
+if sys.version_info < (3, 5):
+	print ('check-static-inits.py: needs python 3.5 for recursive support in glob')
+	sys.exit (77)
+
+OBJS = glob.glob (os.path.join (builddir, libs, '**', '*hb*.o'), recursive=True)
+if not OBJS:
+	print ('check-static-inits.py: object files not found; skipping test')
+	sys.exit (77)
+
+stat = 0
+tested = 0
+
+for obj in OBJS:
+	result = subprocess.run(objdump.split () + ['-t', obj], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+	if result.returncode:
+		if result.stderr.find (b'not recognized') != -1:
+			# https://github.com/harfbuzz/harfbuzz/issues/3019
+			print(('objdump %s returned "not recognized", skipping' % obj))
+			continue
+		print(('objdump %s returned error:\n%s' % (obj, result.stderr.decode ('utf-8'))))
+		stat = 2
+
+	result = result.stdout.decode ('utf-8')
+
+	# Checking that no object file has static initializers
+	for l in re.findall (r'^.*\.[cd]tors.*$', result, re.MULTILINE):
+		if not re.match (r'.*\b0+\b', l):
+			print(('Ouch, %s has static initializers/finalizers' % obj))
+			stat = 1
+
+	# Checking that no object file has lazy static C++ constructors/destructors or other such stuff
+	if ('__cxa_' in result) and ('__ubsan_handle' not in result):
+		print(('Ouch, %s has lazy static C++ constructors/destructors or other such stuff' % obj))
+		stat = 1
+
+	tested += 1
+
+sys.exit (stat if tested else 77)
diff --git a/gfx/harfbuzz/src/check-symbols.py b/gfx/harfbuzz/src/check-symbols.py
index 2a9d58592a..0424584cea 100644
--- a/gfx/harfbuzz/src/check-symbols.py
+++ b/gfx/harfbuzz/src/check-symbols.py
@@ -1,74 +1,75 @@
-#!/usr/bin/env python3
-
-import sys, os, shutil, subprocess, re, difflib
-
-os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
-
-builddir = os.getenv ('builddir', os.path.dirname (__file__))
-libs = os.getenv ('libs', '.libs')
-
-IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
-	'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
-	'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
-	'lprofDirMode', 'reset_fn_list'])
-
-nm = os.getenv ('NM', shutil.which ('nm'))
-if not nm:
-	print ('check-symbols.py: \'nm\' not found; skipping test')
-	sys.exit (77)
-
-cxxfilt = shutil.which ('c++filt')
-
-tested = False
-stat = 0
-
-for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']:
-	for suffix in ['so', 'dylib']:
-		so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
-		if not os.path.exists (so): continue
-
-		# On macOS, C symbols are prefixed with _
-		symprefix = '_' if suffix == 'dylib' else ''
-
-		EXPORTED_SYMBOLS = [s.split ()[2]
-				    for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
-				    if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
-
-		# run again c++filt also if is available
-		if cxxfilt:
-			EXPORTED_SYMBOLS = subprocess.check_output (
-				[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
-			).decode ('utf-8').splitlines ()
-
-		prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
-
-		print ('Checking that %s does not expose internal symbols' % so)
-		suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)]
-		if suspicious_symbols:
-			print ('Ouch, internal symbols exposed:', suspicious_symbols)
-			stat = 1
-
-		def_path = os.path.join (builddir, soname + '.def')
-		if not os.path.exists (def_path):
-			print ('\'%s\' not found; skipping' % def_path)
-		else:
-			print ('Checking that %s has the same symbol list as %s' % (so, def_path))
-			with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read ()
-			diff_result = list (difflib.context_diff (
-				def_file.splitlines (),
-				['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] +
-					# cheat: copy the last line from the def file!
-					[def_file.splitlines ()[-1]]
-			))
-
-			if diff_result:
-				print ('\n'.join (diff_result))
-				stat = 1
-
-			tested = True
-
-if not tested:
-	print ('check-symbols.py: no shared libraries found; skipping test')
-	sys.exit (77)
-
-sys.exit (stat)
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys, os, shutil, subprocess, re, difflib
+
+os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
+
+builddir = os.getenv ('builddir', os.path.dirname (__file__))
+libs = os.getenv ('libs', '.libs')
+
+IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
+	'__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
+	'__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
+	'lprofDirMode', 'reset_fn_list'])
+
+nm = os.getenv ('NM', shutil.which ('nm'))
+if not nm:
+	print ('check-symbols.py: \'nm\' not found; skipping test')
+	sys.exit (77)
+
+cxxfilt = shutil.which ('c++filt')
+
+tested = False
+stat = 0
+
+for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']:
+	for suffix in ['so', 'dylib']:
+		so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
+		if not os.path.exists (so): continue
+
+		# On macOS, C symbols are prefixed with _
+		symprefix = '_' if suffix == 'dylib' else ''
+
+		EXPORTED_SYMBOLS = [s.split ()[2]
+				    for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
+				    if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
+
+		# run again c++filt also if is available
+		if cxxfilt:
+			EXPORTED_SYMBOLS = subprocess.check_output (
+				[cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode ()
+			).decode ('utf-8').splitlines ()
+
+		prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
+
+		print(('Checking that %s does not expose internal symbols' % so))
+		suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)]
+		if suspicious_symbols:
+			print(('Ouch, internal symbols exposed:', suspicious_symbols))
+			stat = 1
+
+		def_path = os.path.join (builddir, soname + '.def')
+		if not os.path.exists (def_path):
+			print(('\'%s\' not found; skipping' % def_path))
+		else:
+			print(('Checking that %s has the same symbol list as %s' % (so, def_path)))
+			with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read ()
+			diff_result = list (difflib.context_diff (
+				def_file.splitlines (),
+				['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] +
+					# cheat: copy the last line from the def file!
+					[def_file.splitlines ()[-1]]
+			))
+
+			if diff_result:
+				print(('\n'.join (diff_result)))
+				stat = 1
+
+			tested = True
+
+if not tested:
+	print ('check-symbols.py: no shared libraries found; skipping test')
+	sys.exit (77)
+
+sys.exit (stat)
diff --git a/gfx/harfbuzz/src/fix_get_types.py b/gfx/harfbuzz/src/fix_get_types.py
index 8e7a08cfda..208b9dfcd6 100644
--- a/gfx/harfbuzz/src/fix_get_types.py
+++ b/gfx/harfbuzz/src/fix_get_types.py
@@ -1,15 +1,15 @@
-#!/usr/bin/env python3
-
-import re
-import argparse
-
-parser = argparse.ArgumentParser ()
-parser.add_argument ('input')
-parser.add_argument ('output')
-args = parser.parse_args ()
-
-with open (args.input, 'r') as inp, open (args.output, 'w') as out:
-    for l in inp.readlines ():
-        l = re.sub ('_t_get_type', '_get_type', l)
-        l = re.sub ('_T \(', ' (', l)
-        out.write (l)
+#!/usr/bin/env python3
+
+import re
+import argparse
+
+parser = argparse.ArgumentParser ()
+parser.add_argument ('input')
+parser.add_argument ('output')
+args = parser.parse_args ()
+
+with open (args.input, 'r') as inp, open (args.output, 'w') as out:
+    for l in inp.readlines ():
+        l = re.sub ('_t_get_type', '_get_type', l)
+        l = re.sub ('_T \(', ' (', l)
+        out.write (l)
diff --git a/gfx/harfbuzz/src/gen-arabic-joining-list.py b/gfx/harfbuzz/src/gen-arabic-joining-list.py
index 6894b84ed9..e40be70cdc 100644
--- a/gfx/harfbuzz/src/gen-arabic-joining-list.py
+++ b/gfx/harfbuzz/src/gen-arabic-joining-list.py
@@ -1,106 +1,107 @@
-#!/usr/bin/env python3
-
-"""usage: ./gen-arabic-joining-table.py ArabicShaping.txt Scripts.txt
-
-Input files:
-* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
-* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
-"""
-
-import os.path, sys
-
-if len (sys.argv) != 3:
-	sys.exit (__doc__)
-
-files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
-
-headers = [[f.readline (), f.readline ()] for f in files]
-while files[0].readline ().find ('##################') < 0:
-	pass
-
-def read (f):
-	mapping = {}
-	for line in f:
-
-		j = line.find ('#')
-		if j >= 0:
-			line = line[:j]
-
-		fields = [x.strip () for x in line.split (';')]
-		if len (fields) == 1:
-			continue
-
-		uu = fields[0].split ('..')
-		start = int (uu[0], 16)
-		if len (uu) == 1:
-			end = start
-		else:
-			end = int (uu[1], 16)
-
-		t = fields[1]
-
-		for u in range (start, end + 1):
-			mapping[u] = t
-
-	return mapping
-
-def read_joining_uu (f):
-	values = set ()
-	for line in f:
-
-		if line[0] == '#':
-			continue
-
-		fields = [x.strip () for x in line.split (';')]
-		if len (fields) == 1:
-			continue
-		if fields[2] in {'T', 'U'}:
-			continue
-
-		values.add (int (fields[0], 16))
-
-	return sorted (values)
-
-def print_has_arabic_joining (scripts, joining_uu):
-
-	print ("static bool")
-	print ("has_arabic_joining (hb_script_t script)")
-	print ("{")
-	print ("  /* List of scripts that have data in arabic-table. */")
-	print ("  switch ((int) script)")
-	print ("  {")
-
-	for script in sorted ({scripts[u] for u in joining_uu if scripts[u] not in {'Common', 'Inherited'}}):
-		print ("    case HB_SCRIPT_{}:".format (script.upper ()))
-
-	print ("      return true;")
-	print ()
-	print ("    default:")
-	print ("      return false;")
-	print ("  }")
-	print ("}")
-	print ()
-
-print ("/* == Start of generated function == */")
-print ("/*")
-print (" * The following function is generated by running:")
-print (" *")
-print (" *   ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt")
-print (" *")
-print (" * on files with these headers:")
-print (" *")
-for h in headers:
-	for l in h:
-		print (" * %s" % (l.strip ()))
-print (" */")
-print ()
-print ("#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
-print ("#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
-print ()
-
-print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
-
-print ()
-print ("#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */")
-print ()
-print ("/* == End of generated function == */")
+#!/usr/bin/env python3
+
+"""usage: ./gen-arabic-joining-table.py ArabicShaping.txt Scripts.txt
+
+Input files:
+* https://unicode.org/Public/UCD/latest/ucd/ArabicShaping.txt
+* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
+"""
+
+from __future__ import print_function
+import os.path, sys
+
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
+
+files = [open (x, encoding='utf-8') for x in sys.argv[1:]]
+
+headers = [[f.readline (), f.readline ()] for f in files]
+while files[0].readline ().find ('##################') < 0:
+	pass
+
+def read (f):
+	mapping = {}
+	for line in f:
+
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+
+		uu = fields[0].split ('..')
+		start = int (uu[0], 16)
+		if len (uu) == 1:
+			end = start
+		else:
+			end = int (uu[1], 16)
+
+		t = fields[1]
+
+		for u in range (start, end + 1):
+			mapping[u] = t
+
+	return mapping
+
+def read_joining_uu (f):
+	values = set ()
+	for line in f:
+
+		if line[0] == '#':
+			continue
+
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+		if fields[2] in {'T', 'U'}:
+			continue
+
+		values.add (int (fields[0], 16))
+
+	return sorted (values)
+
+def print_has_arabic_joining (scripts, joining_uu):
+
+	print ("static bool")
+	print ("has_arabic_joining (hb_script_t script)")
+	print ("{")
+	print ("  /* List of scripts that have data in arabic-table. */")
+	print ("  switch ((int) script)")
+	print ("  {")
+
+	for script in sorted ({scripts[u] for u in joining_uu if scripts[u] not in {'Common', 'Inherited'}}):
+		print(("    case HB_SCRIPT_{}:".format (script.upper ())))
+
+	print ("      return true;")
+	print ()
+	print ("    default:")
+	print ("      return false;")
+	print ("  }")
+	print ("}")
+	print ()
+
+print ("/* == Start of generated function == */")
+print ("/*")
+print (" * The following function is generated by running:")
+print (" *")
+print (" *   ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt")
+print (" *")
+print (" * on files with these headers:")
+print (" *")
+for h in headers:
+	for l in h:
+		print((" * %s" % (l.strip ())))
+print (" */")
+print ()
+print ("#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
+print ("#define HB_OT_SHAPER_ARABIC_JOINING_LIST_HH")
+print ()
+
+print_has_arabic_joining (read (files[1]), read_joining_uu (files[0]))
+
+print ()
+print ("#endif /* HB_OT_SHAPER_ARABIC_JOINING_LIST_HH */")
+print ()
+print ("/* == End of generated function == */")
diff --git a/gfx/harfbuzz/src/gen-arabic-pua.py b/gfx/harfbuzz/src/gen-arabic-pua.py
index 662aa44572..15c2ab7b46 100644
--- a/gfx/harfbuzz/src/gen-arabic-pua.py
+++ b/gfx/harfbuzz/src/gen-arabic-pua.py
@@ -1,35 +1,36 @@
-#!/usr/bin/env python3
-
-"""usage: ./gen-arabic-pua.py
-"""
-
-import packTab
-
-
-print ("/* == Start of generated table == */")
-print ("/*")
-print (" * The following table is generated by running:")
-print (" *")
-print (" *   ./gen-arabic-pua.py")
-print (" *")
-print (" */")
-print ()
-print ("#ifndef HB_OT_SHAPER_ARABIC_PUA_HH")
-print ("#define HB_OT_SHAPER_ARABIC_PUA_HH")
-print ()
-
-code = packTab.Code('_hb_arabic')
-
-for p in ("ArabicPUASimplified.txt", "ArabicPUATraditional.txt"):
-    with open (p, encoding='utf-8') as f:
-        fields = [l.split('\t') for l in f if l[:1] != '#']
-    data = {int(fs[1], 16):int(fs[0], 16) for fs in fields}
-    sol = packTab.pack_table(data, compression=9)
-    sol.genCode(code, f'pua_{p[9:13].lower()}_map')
-
-code.print_c(linkage='static inline')
-
-print ()
-print ("#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */")
-print ()
-print ("/* == End of generated table == */")
+#!/usr/bin/env python3
+
+"""usage: ./gen-arabic-pua.py
+"""
+
+from __future__ import print_function
+import packTab
+
+
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following table is generated by running:")
+print (" *")
+print (" *   ./gen-arabic-pua.py")
+print (" *")
+print (" */")
+print ()
+print ("#ifndef HB_OT_SHAPER_ARABIC_PUA_HH")
+print ("#define HB_OT_SHAPER_ARABIC_PUA_HH")
+print ()
+
+code = packTab.Code('_hb_arabic')
+
+for p in ("ArabicPUASimplified.txt", "ArabicPUATraditional.txt"):
+    with open (p, encoding='utf-8') as f:
+        fields = [l.split('\t') for l in f if l[:1] != '#']
+    data = {int(fs[1], 16):int(fs[0], 16) for fs in fields}
+    sol = packTab.pack_table(data, compression=9)
+    sol.genCode(code, f'pua_{p[9:13].lower()}_map')
+
+code.print_c(linkage='static inline')
+
+print ()
+print ("#endif /* HB_OT_SHAPER_ARABIC_PUA_HH */")
+print ()
+print ("/* == End of generated table == */")
diff --git a/gfx/harfbuzz/src/gen-def.py b/gfx/harfbuzz/src/gen-def.py
index 946a78efca..6011817bc5 100644
--- a/gfx/harfbuzz/src/gen-def.py
+++ b/gfx/harfbuzz/src/gen-def.py
@@ -1,33 +1,33 @@
-#!/usr/bin/env python3
-
-"usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]"
-
-import os, re, sys
-
-if len (sys.argv) < 3:
-	sys.exit(__doc__)
-
-output_file = sys.argv[1]
-header_paths = sys.argv[2:]
-
-headers_content = []
-for h in header_paths:
-	if h.endswith (".h"):
-		with open (h, encoding='utf-8') as f: headers_content.append (f.read ())
-
-symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))
-if '--experimental-api' not in sys.argv:
-	# Move these to harfbuzz-sections.txt when got stable
-	experimental_symbols = \
-"""hb_shape_justify
-hb_subset_repack_or_fail
-hb_subset_input_override_name_table
-""".splitlines ()
-	symbols = [x for x in symbols if x not in experimental_symbols]
-symbols = "\n".join (symbols)
-
-result = symbols if os.getenv ('PLAIN_LIST', '') else """EXPORTS
-%s
-LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', ''))
-
-with open (output_file, "w") as f: f.write (result)
+#!/usr/bin/env python3
+
+"usage: gen-def.py harfbuzz.def hb.h [hb-blob.h hb-buffer.h ...]"
+
+import os, re, sys
+
+if len (sys.argv) < 3:
+	sys.exit(__doc__)
+
+output_file = sys.argv[1]
+header_paths = sys.argv[2:]
+
+headers_content = []
+for h in header_paths:
+	if h.endswith (".h"):
+		with open (h, encoding='utf-8') as f: headers_content.append (f.read ())
+
+symbols = sorted (re.findall (r"^hb_\w+(?= \()", "\n".join (headers_content), re.M))
+if '--experimental-api' not in sys.argv:
+	# Move these to harfbuzz-sections.txt when got stable
+	experimental_symbols = \
+"""hb_shape_justify
+hb_subset_repack_or_fail
+hb_subset_input_override_name_table
+""".splitlines ()
+	symbols = [x for x in symbols if x not in experimental_symbols]
+symbols = "\n".join (symbols)
+
+result = symbols if os.getenv ('PLAIN_LIST', '') else """EXPORTS
+%s
+LIBRARY lib%s-0.dll""" % (symbols, output_file.replace ('src/', '').replace ('.def', ''))
+
+with open (output_file, "w") as f: f.write (result)
diff --git a/gfx/harfbuzz/src/gen-emoji-table.py b/gfx/harfbuzz/src/gen-emoji-table.py
index 3ab3279ab3..ccb3a546ef 100644
--- a/gfx/harfbuzz/src/gen-emoji-table.py
+++ b/gfx/harfbuzz/src/gen-emoji-table.py
@@ -1,98 +1,99 @@
-#!/usr/bin/env python3
-
-"""usage: ./gen-emoji-table.py emoji-data.txt emoji-test.txt
-
-Input file:
-* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
-* https://www.unicode.org/Public/emoji/latest/emoji-test.txt
-"""
-
-import sys
-from collections import OrderedDict
-import packTab
-
-if len (sys.argv) != 3:
-	sys.exit (__doc__)
-
-f = open(sys.argv[1])
-header = [f.readline () for _ in range(10)]
-
-ranges = OrderedDict()
-for line in f.readlines():
-	line = line.strip()
-	if not line or line[0] == '#':
-		continue
-	rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]]
-
-	rang = [int(s, 16) for s in rang.split('..')]
-	if len(rang) > 1:
-		start, end = rang
-	else:
-		start = end = rang[0]
-
-	if typ not in ranges:
-		ranges[typ] = []
-	if ranges[typ] and ranges[typ][-1][1] == start - 1:
-		ranges[typ][-1] = (ranges[typ][-1][0], end)
-	else:
-		ranges[typ].append((start, end))
-
-
-
-print ("/* == Start of generated table == */")
-print ("/*")
-print (" * The following tables are generated by running:")
-print (" *")
-print (" *   ./gen-emoji-table.py emoji-data.txt")
-print (" *")
-print (" * on file with this header:")
-print (" *")
-for l in header:
-	print (" * %s" % (l.strip()))
-print (" */")
-print ()
-print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH")
-print ("#define HB_UNICODE_EMOJI_TABLE_HH")
-print ()
-print ('#include "hb-unicode.hh"')
-print ()
-
-for typ, s in ranges.items():
-	if typ != "Extended_Pictographic": continue
-
-	arr = dict()
-	for start,end in s:
-		for i in range(start, end + 1):
-			arr[i] = 1
-
-	sol = packTab.pack_table(arr, 0, compression=9)
-	code = packTab.Code('_hb_emoji')
-	sol.genCode(code, 'is_'+typ)
-	code.print_c(linkage='static inline')
-	print()
-
-print ()
-print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
-print ()
-print ("/* == End of generated table == */")
-
-
-# Generate test file.
-sequences = []
-with open(sys.argv[2]) as f:
-    for line in f.readlines():
-        if "#" in line:
-            line = line[:line.index("#")]
-        if ";" in line:
-            line = line[:line.index(";")]
-        line = line.strip()
-        line = line.split(" ")
-        if len(line) < 2:
-            continue
-        sequences.append(line)
-
-with open("../test/shape/data/in-house/tests/emoji-clusters.tests", "w") as f:
-    for sequence in sequences:
-        f.write("../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot")
-        f.write(";" + ",".join(sequence))
-        f.write(";[" + "|".join("1=0" for c in sequence) + "]\n")
+#!/usr/bin/env python3
+
+"""usage: ./gen-emoji-table.py emoji-data.txt emoji-test.txt
+
+Input file:
+* https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
+* https://www.unicode.org/Public/emoji/latest/emoji-test.txt
+"""
+
+from __future__ import print_function
+import sys
+from collections import OrderedDict
+import packTab
+
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
+
+f = open(sys.argv[1])
+header = [f.readline () for _ in range(10)]
+
+ranges = OrderedDict()
+for line in f.readlines():
+	line = line.strip()
+	if not line or line[0] == '#':
+		continue
+	rang, typ = [s.strip() for s in line.split('#')[0].split(';')[:2]]
+
+	rang = [int(s, 16) for s in rang.split('..')]
+	if len(rang) > 1:
+		start, end = rang
+	else:
+		start = end = rang[0]
+
+	if typ not in ranges:
+		ranges[typ] = []
+	if ranges[typ] and ranges[typ][-1][1] == start - 1:
+		ranges[typ][-1] = (ranges[typ][-1][0], end)
+	else:
+		ranges[typ].append((start, end))
+
+
+
+print ("/* == Start of generated table == */")
+print ("/*")
+print (" * The following tables are generated by running:")
+print (" *")
+print (" *   ./gen-emoji-table.py emoji-data.txt")
+print (" *")
+print (" * on file with this header:")
+print (" *")
+for l in header:
+	print((" * %s" % (l.strip())))
+print (" */")
+print ()
+print ("#ifndef HB_UNICODE_EMOJI_TABLE_HH")
+print ("#define HB_UNICODE_EMOJI_TABLE_HH")
+print ()
+print ('#include "hb-unicode.hh"')
+print ()
+
+for typ, s in ranges.items():
+	if typ != "Extended_Pictographic": continue
+
+	arr = dict()
+	for start,end in s:
+		for i in range(start, end + 1):
+			arr[i] = 1
+
+	sol = packTab.pack_table(arr, 0, compression=9)
+	code = packTab.Code('_hb_emoji')
+	sol.genCode(code, 'is_'+typ)
+	code.print_c(linkage='static inline')
+	print()
+
+print ()
+print ("#endif /* HB_UNICODE_EMOJI_TABLE_HH */")
+print ()
+print ("/* == End of generated table == */")
+
+
+# Generate test file.
+sequences = []
+with open(sys.argv[2]) as f:
+    for line in f.readlines():
+        if "#" in line:
+            line = line[:line.index("#")]
+        if ";" in line:
+            line = line[:line.index(";")]
+        line = line.strip()
+        line = line.split(" ")
+        if len(line) < 2:
+            continue
+        sequences.append(line)
+
+with open("../test/shape/data/in-house/tests/emoji-clusters.tests", "w") as f:
+    for sequence in sequences:
+        f.write("../fonts/AdobeBlank2.ttf;--no-glyph-names --no-positions --font-funcs=ot")
+        f.write(";" + ",".join(sequence))
+        f.write(";[" + "|".join("1=0" for c in sequence) + "]\n")
diff --git a/gfx/harfbuzz/src/gen-harfbuzzcc.py b/gfx/harfbuzz/src/gen-harfbuzzcc.py
index 4e409b2791..227384043e 100644
--- a/gfx/harfbuzz/src/gen-harfbuzzcc.py
+++ b/gfx/harfbuzz/src/gen-harfbuzzcc.py
@@ -1,24 +1,24 @@
-#!/usr/bin/env python3
-
-"This tool is intended to be used from meson"
-
-import os, sys, shutil
-
-if len (sys.argv) < 3:
-	sys.exit (__doc__)
-
-OUTPUT = sys.argv[1]
-CURRENT_SOURCE_DIR = sys.argv[2]
-
-# make sure input files are unique
-sources = sorted(set(sys.argv[3:]))
-
-with open (OUTPUT, "wb") as f:
-	f.write ("".join ('#include "{}"\n'.format (os.path.relpath (os.path.abspath (x), CURRENT_SOURCE_DIR)) for x in sources if x.endswith (".cc")).encode ())
-
-# copy it also to the source tree, but only if it has changed
-baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
-with open(baseline_filename, "rb") as baseline:
-	with open(OUTPUT, "rb") as generated:
-		if baseline.read() != generated.read():
-			shutil.copyfile (OUTPUT, baseline_filename)
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, sys, shutil
+
+if len (sys.argv) < 3:
+	sys.exit (__doc__)
+
+OUTPUT = sys.argv[1]
+CURRENT_SOURCE_DIR = sys.argv[2]
+
+# make sure input files are unique
+sources = sorted(set(sys.argv[3:]))
+
+with open (OUTPUT, "wb") as f:
+	f.write ("".join ('#include "{}"\n'.format (os.path.relpath (os.path.abspath (x), CURRENT_SOURCE_DIR)) for x in sources if x.endswith (".cc")).encode ())
+
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+	with open(OUTPUT, "rb") as generated:
+		if baseline.read() != generated.read():
+			shutil.copyfile (OUTPUT, baseline_filename)
diff --git a/gfx/harfbuzz/src/gen-hb-version.py b/gfx/harfbuzz/src/gen-hb-version.py
index 9503ad1c1c..06018edfcf 100644
--- a/gfx/harfbuzz/src/gen-hb-version.py
+++ b/gfx/harfbuzz/src/gen-hb-version.py
@@ -1,40 +1,40 @@
-#!/usr/bin/env python3
-
-"This tool is intended to be used from meson"
-
-import os, sys, shutil, re
-
-if len (sys.argv) < 4:
-	sys.exit(__doc__)
-
-version = sys.argv[1]
-major, minor, micro = version.split (".")
-
-OUTPUT = sys.argv[2]
-INPUT = sys.argv[3]
-CURRENT_SOURCE_DIR = os.path.dirname(INPUT)
-
-try:
-	with open (OUTPUT, "r", encoding='utf-8') as old_output:
-		for line in old_output:
-			old_version = re.match (r"#define HB_VERSION_STRING \"(\d.\d.\d)\"", line)
-			if old_version and old_version[1] == version:
-				sys.exit ()
-except IOError:
-	pass
-
-with open (INPUT, "r", encoding='utf-8') as template:
-	with open (OUTPUT, "wb") as output:
-		output.write (template.read ()
-			.replace ("@HB_VERSION_MAJOR@", major)
-			.replace ("@HB_VERSION_MINOR@", minor)
-			.replace ("@HB_VERSION_MICRO@", micro)
-			.replace ("@HB_VERSION@", version)
-			.encode ())
-
-# copy it also to the source tree, but only if it has changed
-baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
-with open(baseline_filename, "rb") as baseline:
-	with open(OUTPUT, "rb") as generated:
-		if baseline.read() != generated.read():
-			shutil.copyfile (OUTPUT, baseline_filename)
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, sys, shutil, re
+
+if len (sys.argv) < 4:
+	sys.exit(__doc__)
+
+version = sys.argv[1]
+major, minor, micro = version.split (".")
+
+OUTPUT = sys.argv[2]
+INPUT = sys.argv[3]
+CURRENT_SOURCE_DIR = os.path.dirname(INPUT)
+
+try:
+	with open (OUTPUT, "r", encoding='utf-8') as old_output:
+		for line in old_output:
+			old_version = re.match (r"#define HB_VERSION_STRING \"(\d.\d.\d)\"", line)
+			if old_version and old_version[1] == version:
+				sys.exit ()
+except IOError:
+	pass
+
+with open (INPUT, "r", encoding='utf-8') as template:
+	with open (OUTPUT, "wb") as output:
+		output.write (template.read ()
+			.replace ("@HB_VERSION_MAJOR@", major)
+			.replace ("@HB_VERSION_MINOR@", minor)
+			.replace ("@HB_VERSION_MICRO@", micro)
+			.replace ("@HB_VERSION@", version)
+			.encode ())
+
+# copy it also to the source tree, but only if it has changed
+baseline_filename = os.path.join (CURRENT_SOURCE_DIR, os.path.basename (OUTPUT))
+with open(baseline_filename, "rb") as baseline:
+	with open(OUTPUT, "rb") as generated:
+		if baseline.read() != generated.read():
+			shutil.copyfile (OUTPUT, baseline_filename)
diff --git a/gfx/harfbuzz/src/gen-os2-unicode-ranges.py b/gfx/harfbuzz/src/gen-os2-unicode-ranges.py
index b8b6489dfc..d7e5f27203 100644
--- a/gfx/harfbuzz/src/gen-os2-unicode-ranges.py
+++ b/gfx/harfbuzz/src/gen-os2-unicode-ranges.py
@@ -1,50 +1,51 @@
-#!/usr/bin/env python3
-
-"""Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
-Input is a tab separated list of unicode ranges from the otspec
-(https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
-"""
-
-import re
-import sys
-
-
-print ("""static OS2Range _hb_os2_unicode_ranges[] =
-{""")
-
-args = sys.argv[1:]
-input_file = args[0]
-
-with open (input_file, mode="r", encoding="utf-8") as f:
-
-  all_ranges = []
-  current_bit = 0
-  while True:
-    line = f.readline().strip()
-    if not line:
-      break
-    fields = re.split(r'\t+', line)
-    if len(fields) == 3:
-      current_bit = fields[0]
-      fields = fields[1:]
-    elif len(fields) > 3:
-      raise Exception("bad input :(.")
-
-    name = fields[0]
-    ranges = re.split("-", fields[1])
-    if len(ranges) != 2:
-      raise Exception("bad input :(.")
-
-    v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name))
-    all_ranges.append(v)
-
-all_ranges = sorted(all_ranges, key=lambda t: t[0])
-
-for ranges in all_ranges:
-  start = ("0x%X" % ranges[0]).rjust(8)
-  end = ("0x%X" % ranges[1]).rjust(8)
-  bit = ("%s" % ranges[2]).rjust(3)
-
-  print ("  {%s, %s, %s}, // %s" % (start, end, bit, ranges[3]))
-
-print ("""};""")
+#!/usr/bin/env python3
+
+"""Generates the code for a sorted unicode range array as used in hb-ot-os2-unicode-ranges.hh
+Input is a tab separated list of unicode ranges from the otspec
+(https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ur).
+"""
+
+from __future__ import print_function
+import re
+import sys
+
+
+print ("""static OS2Range _hb_os2_unicode_ranges[] =
+{""")
+
+args = sys.argv[1:]
+input_file = args[0]
+
+with open (input_file, mode="r", encoding="utf-8") as f:
+
+  all_ranges = []
+  current_bit = 0
+  while True:
+    line = f.readline().strip()
+    if not line:
+      break
+    fields = re.split(r'\t+', line)
+    if len(fields) == 3:
+      current_bit = fields[0]
+      fields = fields[1:]
+    elif len(fields) > 3:
+      raise Exception("bad input :(.")
+
+    name = fields[0]
+    ranges = re.split("-", fields[1])
+    if len(ranges) != 2:
+      raise Exception("bad input :(.")
+
+    v = tuple((int(ranges[0], 16), int(ranges[1], 16), int(current_bit), name))
+    all_ranges.append(v)
+
+all_ranges = sorted(all_ranges, key=lambda t: t[0])
+
+for ranges in all_ranges:
+  start = ("0x%X" % ranges[0]).rjust(8)
+  end = ("0x%X" % ranges[1]).rjust(8)
+  bit = ("%s" % ranges[2]).rjust(3)
+
+  print(("  {%s, %s, %s}, // %s" % (start, end, bit, ranges[3])))
+
+print ("""};""")
diff --git a/gfx/harfbuzz/src/gen-ragel-artifacts.py b/gfx/harfbuzz/src/gen-ragel-artifacts.py
index fa235f0e9a..8bbb375bfb 100644
--- a/gfx/harfbuzz/src/gen-ragel-artifacts.py
+++ b/gfx/harfbuzz/src/gen-ragel-artifacts.py
@@ -1,25 +1,25 @@
-#!/usr/bin/env python3
-
-"This tool is intended to be used from meson"
-
-import os, os.path, sys, subprocess, shutil
-
-ragel = sys.argv[1]
-if not ragel:
-	sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself')
-
-if len (sys.argv) < 4:
-	sys.exit (__doc__)
-
-OUTPUT = sys.argv[2]
-CURRENT_SOURCE_DIR = sys.argv[3]
-INPUT = sys.argv[4]
-
-outdir = os.path.dirname (OUTPUT)
-shutil.copy (INPUT, outdir)
-rl = os.path.basename (INPUT)
-hh = rl.replace ('.rl', '.hh')
-subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
-
-# copy it also to src/
-shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
+#!/usr/bin/env python3
+
+"This tool is intended to be used from meson"
+
+import os, os.path, sys, subprocess, shutil
+
+ragel = sys.argv[1]
+if not ragel:
+	sys.exit ('You have to install ragel if you are going to develop HarfBuzz itself')
+
+if len (sys.argv) < 4:
+	sys.exit (__doc__)
+
+OUTPUT = sys.argv[2]
+CURRENT_SOURCE_DIR = sys.argv[3]
+INPUT = sys.argv[4]
+
+outdir = os.path.dirname (OUTPUT)
+shutil.copy (INPUT, outdir)
+rl = os.path.basename (INPUT)
+hh = rl.replace ('.rl', '.hh')
+subprocess.Popen (ragel.split() + ['-e', '-F1', '-o', hh, rl], cwd=outdir).wait ()
+
+# copy it also to src/
+shutil.copyfile (os.path.join (outdir, hh), os.path.join (CURRENT_SOURCE_DIR, hh))
diff --git a/gfx/harfbuzz/src/gen-tag-table.py b/gfx/harfbuzz/src/gen-tag-table.py
index 54817a6ed0..35819800d3 100644
--- a/gfx/harfbuzz/src/gen-tag-table.py
+++ b/gfx/harfbuzz/src/gen-tag-table.py
@@ -1,1216 +1,1216 @@
-#!/usr/bin/env python3
-
-"""Generator of the mapping from OpenType tags to BCP 47 tags and vice
-versa.
-
-It creates a ``const LangTag[]``, matching the tags from the OpenType
-languages system tag list to the language subtags of the BCP 47 language
-subtag registry, with some manual adjustments. The mappings are
-supplemented with macrolanguages' sublanguages and retired codes'
-replacements, according to BCP 47 and some manual additions where BCP 47
-omits a retired code entirely.
-
-Also generated is a function, ``hb_ot_ambiguous_tag_to_language``,
-intended for use by ``hb_ot_tag_to_language``. It maps OpenType tags
-back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to
-multiple BCP 47 tags) are listed here, except when the alphabetically
-first BCP 47 tag happens to be the chosen disambiguated tag. In that
-case, the fallback behavior will choose the right tag anyway.
-
-usage: ./gen-tag-table.py languagetags language-subtag-registry
-
-Input files:
-* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
-* https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
-"""
-
-import collections
-import html
-from html.parser import HTMLParser
-import itertools
-import re
-import sys
-import unicodedata
-
-if len (sys.argv) != 3:
-	sys.exit (__doc__)
-
-def expect (condition, message=None):
-	if not condition:
-		if message is None:
-			raise AssertionError
-		raise AssertionError (message)
-
-def write (s):
-	sys.stdout.flush ()
-	sys.stdout.buffer.write (s.encode ('utf-8'))
-
-DEFAULT_LANGUAGE_SYSTEM = ''
-
-# from https://www-01.sil.org/iso639-3/iso-639-3.tab
-ISO_639_3_TO_1 = {
-	'aar': 'aa',
-	'abk': 'ab',
-	'afr': 'af',
-	'aka': 'ak',
-	'amh': 'am',
-	'ara': 'ar',
-	'arg': 'an',
-	'asm': 'as',
-	'ava': 'av',
-	'ave': 'ae',
-	'aym': 'ay',
-	'aze': 'az',
-	'bak': 'ba',
-	'bam': 'bm',
-	'bel': 'be',
-	'ben': 'bn',
-	'bis': 'bi',
-	'bod': 'bo',
-	'bos': 'bs',
-	'bre': 'br',
-	'bul': 'bg',
-	'cat': 'ca',
-	'ces': 'cs',
-	'cha': 'ch',
-	'che': 'ce',
-	'chu': 'cu',
-	'chv': 'cv',
-	'cor': 'kw',
-	'cos': 'co',
-	'cre': 'cr',
-	'cym': 'cy',
-	'dan': 'da',
-	'deu': 'de',
-	'div': 'dv',
-	'dzo': 'dz',
-	'ell': 'el',
-	'eng': 'en',
-	'epo': 'eo',
-	'est': 'et',
-	'eus': 'eu',
-	'ewe': 'ee',
-	'fao': 'fo',
-	'fas': 'fa',
-	'fij': 'fj',
-	'fin': 'fi',
-	'fra': 'fr',
-	'fry': 'fy',
-	'ful': 'ff',
-	'gla': 'gd',
-	'gle': 'ga',
-	'glg': 'gl',
-	'glv': 'gv',
-	'grn': 'gn',
-	'guj': 'gu',
-	'hat': 'ht',
-	'hau': 'ha',
-	'hbs': 'sh',
-	'heb': 'he',
-	'her': 'hz',
-	'hin': 'hi',
-	'hmo': 'ho',
-	'hrv': 'hr',
-	'hun': 'hu',
-	'hye': 'hy',
-	'ibo': 'ig',
-	'ido': 'io',
-	'iii': 'ii',
-	'iku': 'iu',
-	'ile': 'ie',
-	'ina': 'ia',
-	'ind': 'id',
-	'ipk': 'ik',
-	'isl': 'is',
-	'ita': 'it',
-	'jav': 'jv',
-	'jpn': 'ja',
-	'kal': 'kl',
-	'kan': 'kn',
-	'kas': 'ks',
-	'kat': 'ka',
-	'kau': 'kr',
-	'kaz': 'kk',
-	'khm': 'km',
-	'kik': 'ki',
-	'kin': 'rw',
-	'kir': 'ky',
-	'kom': 'kv',
-	'kon': 'kg',
-	'kor': 'ko',
-	'kua': 'kj',
-	'kur': 'ku',
-	'lao': 'lo',
-	'lat': 'la',
-	'lav': 'lv',
-	'lim': 'li',
-	'lin': 'ln',
-	'lit': 'lt',
-	'ltz': 'lb',
-	'lub': 'lu',
-	'lug': 'lg',
-	'mah': 'mh',
-	'mal': 'ml',
-	'mar': 'mr',
-	'mkd': 'mk',
-	'mlg': 'mg',
-	'mlt': 'mt',
-	'mol': 'mo',
-	'mon': 'mn',
-	'mri': 'mi',
-	'msa': 'ms',
-	'mya': 'my',
-	'nau': 'na',
-	'nav': 'nv',
-	'nbl': 'nr',
-	'nde': 'nd',
-	'ndo': 'ng',
-	'nep': 'ne',
-	'nld': 'nl',
-	'nno': 'nn',
-	'nob': 'nb',
-	'nor': 'no',
-	'nya': 'ny',
-	'oci': 'oc',
-	'oji': 'oj',
-	'ori': 'or',
-	'orm': 'om',
-	'oss': 'os',
-	'pan': 'pa',
-	'pli': 'pi',
-	'pol': 'pl',
-	'por': 'pt',
-	'pus': 'ps',
-	'que': 'qu',
-	'roh': 'rm',
-	'ron': 'ro',
-	'run': 'rn',
-	'rus': 'ru',
-	'sag': 'sg',
-	'san': 'sa',
-	'sin': 'si',
-	'slk': 'sk',
-	'slv': 'sl',
-	'sme': 'se',
-	'smo': 'sm',
-	'sna': 'sn',
-	'snd': 'sd',
-	'som': 'so',
-	'sot': 'st',
-	'spa': 'es',
-	'sqi': 'sq',
-	'srd': 'sc',
-	'srp': 'sr',
-	'ssw': 'ss',
-	'sun': 'su',
-	'swa': 'sw',
-	'swe': 'sv',
-	'tah': 'ty',
-	'tam': 'ta',
-	'tat': 'tt',
-	'tel': 'te',
-	'tgk': 'tg',
-	'tgl': 'tl',
-	'tha': 'th',
-	'tir': 'ti',
-	'ton': 'to',
-	'tsn': 'tn',
-	'tso': 'ts',
-	'tuk': 'tk',
-	'tur': 'tr',
-	'twi': 'tw',
-	'uig': 'ug',
-	'ukr': 'uk',
-	'urd': 'ur',
-	'uzb': 'uz',
-	'ven': 've',
-	'vie': 'vi',
-	'vol': 'vo',
-	'wln': 'wa',
-	'wol': 'wo',
-	'xho': 'xh',
-	'yid': 'yi',
-	'yor': 'yo',
-	'zha': 'za',
-	'zho': 'zh',
-	'zul': 'zu',
-}
-
-class LanguageTag (object):
-	"""A BCP 47 language tag.
-
-	Attributes:
-		subtags (List[str]): The list of subtags in this tag.
-		grandfathered (bool): Whether this tag is grandfathered. If
-			``true``, the entire lowercased tag is the ``language``
-			and the other subtag fields are empty.
-		language (str): The language subtag.
-		script (str): The script subtag.
-		region (str): The region subtag.
-		variant (str): The variant subtag.
-
-	Args:
-		tag (str): A BCP 47 language tag.
-
-	"""
-	def __init__ (self, tag):
-		global bcp_47
-		self.subtags = tag.lower ().split ('-')
-		self.grandfathered = tag.lower () in bcp_47.grandfathered
-		if self.grandfathered:
-			self.language = tag.lower ()
-			self.script = ''
-			self.region = ''
-			self.variant = ''
-		else:
-			self.language = self.subtags[0]
-			self.script = self._find_first (lambda s: len (s) == 4 and s[0] > '9', self.subtags)
-			self.region = self._find_first (lambda s: len (s) == 2 and s[0] > '9' or len (s) == 3 and s[0] <= '9', self.subtags[1:])
-			self.variant = self._find_first (lambda s: len (s) > 4 or len (s) == 4 and s[0] <= '9', self.subtags)
-
-	def __str__(self):
-		return '-'.join(self.subtags)
-
-	def __repr__ (self):
-		return 'LanguageTag(%r)' % str(self)
-
-	@staticmethod
-	def _find_first (function, sequence):
-		try:
-			return next (iter (filter (function, sequence)))
-		except StopIteration:
-			return None
-
-	def is_complex (self):
-		"""Return whether this tag is too complex to represent as a
-		``LangTag`` in the generated code.
-
-		Complex tags need to be handled in
-		``hb_ot_tags_from_complex_language``.
-
-		Returns:
-			Whether this tag is complex.
-		"""
-		return not (len (self.subtags) == 1
-			or self.grandfathered
-			and len (self.subtags[1]) != 3
-			and ot.from_bcp_47[self.subtags[0]] == ot.from_bcp_47[self.language])
-
-	def get_group (self):
-		"""Return the group into which this tag should be categorized in
-		``hb_ot_tags_from_complex_language``.
-
-		The group is the first letter of the tag, or ``'und'`` if this tag
-		should not be matched in a ``switch`` statement in the generated
-		code.
-
-		Returns:
-			This tag's group.
-		"""
-		return ('und'
-			if (self.language == 'und'
-				or self.variant in bcp_47.prefixes and len (bcp_47.prefixes[self.variant]) == 1)
-			else self.language[0])
-
-class OpenTypeRegistryParser (HTMLParser):
-	"""A parser for the OpenType language system tag registry.
-
-	Attributes:
-		header (str): The "last updated" line of the registry.
-		names (Mapping[str, str]): A map of language system tags to the
-			names they are given in the registry.
-		ranks (DefaultDict[str, int]): A map of language system tags to
-			numbers. If a single BCP 47 tag corresponds to multiple
-			OpenType tags, the tags are ordered in increasing order by
-			rank. The rank is based on the number of BCP 47 tags
-			associated with a tag, though it may be manually modified.
-		to_bcp_47 (DefaultDict[str, AbstractSet[str]]): A map of
-			OpenType language system tags to sets of BCP 47 tags.
-		from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47``
-			inverted. Its values start as unsorted sets;
-			``sort_languages`` converts them to sorted lists.
-		from_bcp_47_uninherited (Optional[Dict[str, AbstractSet[str]]]):
-			A copy of ``from_bcp_47``. It starts as ``None`` and is
-			populated at the beginning of the first call to
-			``inherit_from_macrolanguages``.
-
-	"""
-	def __init__ (self):
-		HTMLParser.__init__ (self)
-		self.header = ''
-		self.names = {}
-		self.ranks = collections.defaultdict (int)
-		self.to_bcp_47 = collections.defaultdict (set)
-		self.from_bcp_47 = collections.defaultdict (set)
-		self.from_bcp_47_uninherited = None
-		# Whether the parser is in a <td> element
-		self._td = False
-		# Whether the parser is after a <br> element within the current <tr> element
-		self._br = False
-		# The text of the <td> elements of the current <tr> element.
-		self._current_tr = []
-
-	def handle_starttag (self, tag, attrs):
-		if tag == 'br':
-			self._br = True
-		elif tag == 'meta':
-			for attr, value in attrs:
-				if attr == 'name' and value == 'updated_at':
-					self.header = self.get_starttag_text ()
-					break
-		elif tag == 'td':
-			self._td = True
-			self._current_tr.append ('')
-		elif tag == 'tr':
-			self._br = False
-			self._current_tr = []
-
-	def handle_endtag (self, tag):
-		if tag == 'td':
-			self._td = False
-		elif tag == 'tr' and self._current_tr:
-			expect (2 <= len (self._current_tr) <= 3)
-			name = self._current_tr[0].strip ()
-			tag = self._current_tr[1].strip ("\t\n\v\f\r '")
-			rank = 0
-			if len (tag) > 4:
-				expect (tag.endswith (' (deprecated)'), 'ill-formed OpenType tag: %s' % tag)
-				name += ' (deprecated)'
-				tag = tag.split (' ')[0]
-				rank = 1
-			self.names[tag] = re.sub (' languages$', '', name)
-			if not self._current_tr[2]:
-				return
-			iso_codes = self._current_tr[2].strip ()
-			self.to_bcp_47[tag].update (ISO_639_3_TO_1.get (code, code) for code in iso_codes.replace (' ', '').split (','))
-			rank += 2 * len (self.to_bcp_47[tag])
-			self.ranks[tag] = rank
-
-	def handle_data (self, data):
-		if self._td and not self._br:
-			self._current_tr[-1] += data
-
-	def handle_charref (self, name):
-		self.handle_data (html.unescape ('&#%s;' % name))
-
-	def handle_entityref (self, name):
-		self.handle_data (html.unescape ('&%s;' % name))
-
-	def parse (self, filename):
-		"""Parse the OpenType language system tag registry.
-
-		Args:
-			filename (str): The file name of the registry.
-		"""
-		with open (filename, encoding='utf-8') as f:
-			self.feed (f.read ())
-		expect (self.header)
-		for tag, iso_codes in self.to_bcp_47.items ():
-			for iso_code in iso_codes:
-				self.from_bcp_47[iso_code].add (tag)
-
-	def add_language (self, bcp_47_tag, ot_tag):
-		"""Add a language as if it were in the registry.
-
-		Args:
-			bcp_47_tag (str): A BCP 47 tag. If the tag is more than just
-				a language subtag, and if the language subtag is a
-				macrolanguage, then new languages are added corresponding
-				to the macrolanguages' individual languages with the
-				remainder of the tag appended.
-			ot_tag (str): An OpenType language system tag.
-		"""
-		global bcp_47
-		self.to_bcp_47[ot_tag].add (bcp_47_tag)
-		self.from_bcp_47[bcp_47_tag].add (ot_tag)
-		if bcp_47_tag.lower () not in bcp_47.grandfathered:
-			try:
-				[macrolanguage, suffix] = bcp_47_tag.split ('-', 1)
-				if macrolanguage in bcp_47.macrolanguages:
-					s = set ()
-					for language in bcp_47.macrolanguages[macrolanguage]:
-						if language.lower () not in bcp_47.grandfathered:
-							s.add ('%s-%s' % (language, suffix))
-					bcp_47.macrolanguages['%s-%s' % (macrolanguage, suffix)] = s
-			except ValueError:
-				pass
-
-	@staticmethod
-	def _remove_language (tag_1, dict_1, dict_2):
-		for tag_2 in dict_1.pop (tag_1):
-			dict_2[tag_2].remove (tag_1)
-			if not dict_2[tag_2]:
-				del dict_2[tag_2]
-
-	def remove_language_ot (self, ot_tag):
-		"""Remove an OpenType tag from the registry.
-
-		Args:
-			ot_tag (str): An OpenType tag.
-		"""
-		self._remove_language (ot_tag, self.to_bcp_47, self.from_bcp_47)
-
-	def remove_language_bcp_47 (self, bcp_47_tag):
-		"""Remove a BCP 47 tag from the registry.
-
-		Args:
-			bcp_47_tag (str): A BCP 47 tag.
-		"""
-		self._remove_language (bcp_47_tag, self.from_bcp_47, self.to_bcp_47)
-
-	def inherit_from_macrolanguages (self):
-		"""Copy mappings from macrolanguages to individual languages.
-
-		If a BCP 47 tag for an individual mapping has no OpenType
-		mapping but its macrolanguage does, the mapping is copied to
-		the individual language. For example, als (Tosk Albanian) has no
-		explicit mapping, so it inherits from sq (Albanian) the mapping
-		to SQI.
-
-		However, if an OpenType tag maps to a BCP 47 macrolanguage and
-		some but not all of its individual languages, the mapping is not
-		inherited from the macrolanguage to the missing individual
-		languages. For example, INUK (Nunavik Inuktitut) is mapped to
-		ike (Eastern Canadian Inuktitut) and iu (Inuktitut) but not to
-		ikt (Inuinnaqtun, which is an individual language of iu), so
-		this method does not add a mapping from ikt to INUK.
-
-		If a BCP 47 tag for a macrolanguage has no OpenType mapping but
-		some of its individual languages do, their mappings are copied
-		to the macrolanguage.
-		"""
-		global bcp_47
-		first_time = self.from_bcp_47_uninherited is None
-		if first_time:
-			self.from_bcp_47_uninherited = dict (self.from_bcp_47)
-		for macrolanguage, languages in dict (bcp_47.macrolanguages).items ():
-			ot_macrolanguages = {
-				ot_macrolanguage for ot_macrolanguage in self.from_bcp_47_uninherited.get (macrolanguage, set ())
-			}
-			blocked_ot_macrolanguages = set ()
-			if 'retired code' not in bcp_47.scopes.get (macrolanguage, ''):
-				for ot_macrolanguage in ot_macrolanguages:
-					round_trip_macrolanguages = {
-						l for l in self.to_bcp_47[ot_macrolanguage]
-						if 'retired code' not in bcp_47.scopes.get (l, '')
-					}
-					round_trip_languages = {
-						l for l in languages
-						if 'retired code' not in bcp_47.scopes.get (l, '')
-					}
-					intersection = round_trip_macrolanguages & round_trip_languages
-					if intersection and intersection != round_trip_languages:
-						blocked_ot_macrolanguages.add (ot_macrolanguage)
-			if ot_macrolanguages:
-				for ot_macrolanguage in ot_macrolanguages:
-					if ot_macrolanguage not in blocked_ot_macrolanguages:
-						for language in languages:
-							self.add_language (language, ot_macrolanguage)
-							if not blocked_ot_macrolanguages:
-								self.ranks[ot_macrolanguage] += 1
-			elif first_time:
-				for language in languages:
-					if language in self.from_bcp_47_uninherited:
-						ot_macrolanguages |= self.from_bcp_47_uninherited[language]
-					else:
-						ot_macrolanguages.clear ()
-					if not ot_macrolanguages:
-						break
-				for ot_macrolanguage in ot_macrolanguages:
-					self.add_language (macrolanguage, ot_macrolanguage)
-
-	def sort_languages (self):
-		"""Sort the values of ``from_bcp_47`` in ascending rank order."""
-		for language, tags in self.from_bcp_47.items ():
-			self.from_bcp_47[language] = sorted (tags,
-					key=lambda t: (self.ranks[t] + rank_delta (language, t), t))
-
-ot = OpenTypeRegistryParser ()
-
-class BCP47Parser (object):
-	"""A parser for the BCP 47 subtag registry.
-
-	Attributes:
-		header (str): The "File-Date" line of the registry.
-		names (Mapping[str, str]): A map of subtags to the names they
-			are given in the registry. Each value is a
-			``'\\n'``-separated list of names.
-		scopes (Mapping[str, str]): A map of language subtags to strings
-			suffixed to language names, including suffixes to explain
-			language scopes.
-		macrolanguages (DefaultDict[str, AbstractSet[str]]): A map of
-			language subtags to the sets of language subtags which
-			inherit from them. See
-			``OpenTypeRegistryParser.inherit_from_macrolanguages``.
-		prefixes (DefaultDict[str, AbstractSet[str]]): A map of variant
-			subtags to their prefixes.
-		grandfathered (AbstractSet[str]): The set of grandfathered tags,
-			normalized to lowercase.
-
-	"""
-	def __init__ (self):
-		self.header = ''
-		self.names = {}
-		self.scopes = {}
-		self.macrolanguages = collections.defaultdict (set)
-		self.prefixes = collections.defaultdict (set)
-		self.grandfathered = set ()
-
-	def parse (self, filename):
-		"""Parse the BCP 47 subtag registry.
-
-		Args:
-			filename (str): The file name of the registry.
-		"""
-		with open (filename, encoding='utf-8') as f:
-			subtag_type = None
-			subtag = None
-			deprecated = False
-			has_preferred_value = False
-			line_buffer = ''
-			for line in itertools.chain (f, ['']):
-				line = line.rstrip ()
-				if line.startswith (' '):
-					line_buffer += line[1:]
-					continue
-				line, line_buffer = line_buffer, line
-				if line.startswith ('Type: '):
-					subtag_type = line.split (' ')[1]
-					deprecated = False
-					has_preferred_value = False
-				elif line.startswith ('Subtag: ') or line.startswith ('Tag: '):
-					subtag = line.split (' ')[1]
-					if subtag_type == 'grandfathered':
-						self.grandfathered.add (subtag.lower ())
-				elif line.startswith ('Description: '):
-					description = line.split (' ', 1)[1].replace (' (individual language)', '')
-					description = re.sub (' (\(family\)|\((individual |macro)language\)|languages)$', '',
-							description)
-					if subtag in self.names:
-						self.names[subtag] += '\n' + description
-					else:
-						self.names[subtag] = description
-				elif subtag_type == 'language' or subtag_type == 'grandfathered':
-					if line.startswith ('Scope: '):
-						scope = line.split (' ')[1]
-						if scope == 'macrolanguage':
-							scope = ' [macrolanguage]'
-						elif scope == 'collection':
-							scope = ' [collection]'
-						else:
-							continue
-						self.scopes[subtag] = scope
-					elif line.startswith ('Deprecated: '):
-						self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
-						deprecated = True
-					elif deprecated and line.startswith ('Comments: see '):
-						# If a subtag is split into multiple replacement subtags,
-						# it essentially represents a macrolanguage.
-						for language in line.replace (',', '').split (' ')[2:]:
-							self._add_macrolanguage (subtag, language)
-					elif line.startswith ('Preferred-Value: '):
-						# If a subtag is deprecated in favor of a single replacement subtag,
-						# it is either a dialect or synonym of the preferred subtag. Either
-						# way, it is close enough to the truth to consider the replacement
-						# the macrolanguage of the deprecated language.
-						has_preferred_value = True
-						macrolanguage = line.split (' ')[1]
-						self._add_macrolanguage (macrolanguage, subtag)
-					elif not has_preferred_value and line.startswith ('Macrolanguage: '):
-						self._add_macrolanguage (line.split (' ')[1], subtag)
-				elif subtag_type == 'variant':
-					if line.startswith ('Deprecated: '):
-						self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
-					elif line.startswith ('Prefix: '):
-						self.prefixes[subtag].add (line.split (' ')[1])
-				elif line.startswith ('File-Date: '):
-					self.header = line
-		expect (self.header)
-
-	def _add_macrolanguage (self, macrolanguage, language):
-		global ot
-		if language not in ot.from_bcp_47:
-			for l in self.macrolanguages.get (language, set ()):
-				self._add_macrolanguage (macrolanguage, l)
-		if macrolanguage not in ot.from_bcp_47:
-			for ls in list (self.macrolanguages.values ()):
-				if macrolanguage in ls:
-					ls.add (language)
-					return
-		self.macrolanguages[macrolanguage].add (language)
-
-	def remove_extra_macrolanguages (self):
-		"""Make every language have at most one macrolanguage."""
-		inverted = collections.defaultdict (list)
-		for macrolanguage, languages in self.macrolanguages.items ():
-			for language in languages:
-				inverted[language].append (macrolanguage)
-		for language, macrolanguages in inverted.items ():
-			if len (macrolanguages) > 1:
-				macrolanguages.sort (key=lambda ml: len (self.macrolanguages[ml]))
-				biggest_macrolanguage = macrolanguages.pop ()
-				for macrolanguage in macrolanguages:
-					self._add_macrolanguage (biggest_macrolanguage, macrolanguage)
-
-	def _get_name_piece (self, subtag):
-		"""Return the first name of a subtag plus its scope suffix.
-
-		Args:
-			subtag (str): A BCP 47 subtag.
-
-		Returns:
-			The name form of ``subtag``.
-		"""
-		return self.names[subtag].split ('\n')[0] + self.scopes.get (subtag, '')
-
-	def get_name (self, lt):
-		"""Return the names of the subtags in a language tag.
-
-		Args:
-			lt (LanguageTag): A BCP 47 language tag.
-
-		Returns:
-			The name form of ``lt``.
-		"""
-		name = self._get_name_piece (lt.language)
-		if lt.script:
-			name += '; ' + self._get_name_piece (lt.script.title ())
-		if lt.region:
-			name += '; ' + self._get_name_piece (lt.region.upper ())
-		if lt.variant:
-			name += '; ' + self._get_name_piece (lt.variant)
-		return name
-
-bcp_47 = BCP47Parser ()
-
-ot.parse (sys.argv[1])
-bcp_47.parse (sys.argv[2])
-
-ot.add_language ('ary', 'MOR')
-
-ot.add_language ('ath', 'ATH')
-
-ot.add_language ('bai', 'BML')
-
-ot.ranks['BAL'] = ot.ranks['KAR'] + 1
-
-ot.add_language ('ber', 'BBR')
-
-ot.remove_language_ot ('PGR')
-ot.add_language ('el-polyton', 'PGR')
-
-bcp_47.macrolanguages['et'] = {'ekk'}
-
-bcp_47.names['flm'] = 'Falam Chin'
-bcp_47.scopes['flm'] = ' (retired code)'
-bcp_47.macrolanguages['flm'] = {'cfm'}
-
-ot.ranks['FNE'] = ot.ranks['TNE'] + 1
-
-ot.add_language ('und-fonipa', 'IPPH')
-
-ot.add_language ('und-fonnapa', 'APPH')
-
-ot.remove_language_ot ('IRT')
-ot.add_language ('ga-Latg', 'IRT')
-
-ot.add_language ('hy-arevmda', 'HYE')
-
-ot.remove_language_ot ('KGE')
-ot.add_language ('und-Geok', 'KGE')
-
-bcp_47.macrolanguages['id'] = {'in'}
-
-bcp_47.macrolanguages['ijo'] = {'ijc'}
-
-ot.add_language ('kht', 'KHN')
-ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)'
-ot.ranks['KHN'] = ot.ranks['KHT'] + 1
-
-ot.ranks['LCR'] = ot.ranks['MCR'] + 1
-
-ot.names['MAL'] = 'Malayalam Traditional'
-ot.ranks['MLR'] += 1
-
-bcp_47.names['mhv'] = 'Arakanese'
-bcp_47.scopes['mhv'] = ' (retired code)'
-
-ot.add_language ('mnw-TH', 'MONT')
-
-ot.add_language ('no', 'NOR')
-
-ot.add_language ('oc-provenc', 'PRO')
-
-ot.remove_language_ot ('QUZ')
-ot.add_language ('qu', 'QUZ')
-ot.add_language ('qub', 'QWH')
-ot.add_language ('qud', 'QVI')
-ot.add_language ('qug', 'QVI')
-ot.add_language ('qul', 'QUH')
-ot.add_language ('qup', 'QVI')
-ot.add_language ('qur', 'QWH')
-ot.add_language ('qus', 'QUH')
-ot.add_language ('quw', 'QVI')
-ot.add_language ('qux', 'QWH')
-ot.add_language ('qva', 'QWH')
-ot.add_language ('qvh', 'QWH')
-ot.add_language ('qvj', 'QVI')
-ot.add_language ('qvl', 'QWH')
-ot.add_language ('qvm', 'QWH')
-ot.add_language ('qvn', 'QWH')
-ot.add_language ('qvo', 'QVI')
-ot.add_language ('qvp', 'QWH')
-ot.add_language ('qvw', 'QWH')
-ot.add_language ('qvz', 'QVI')
-ot.add_language ('qwa', 'QWH')
-ot.add_language ('qws', 'QWH')
-ot.add_language ('qxa', 'QWH')
-ot.add_language ('qxc', 'QWH')
-ot.add_language ('qxh', 'QWH')
-ot.add_language ('qxl', 'QVI')
-ot.add_language ('qxn', 'QWH')
-ot.add_language ('qxo', 'QWH')
-ot.add_language ('qxr', 'QVI')
-ot.add_language ('qxt', 'QWH')
-ot.add_language ('qxw', 'QWH')
-
-bcp_47.macrolanguages['ro-MD'].add ('mo')
-
-ot.remove_language_ot ('SYRE')
-ot.remove_language_ot ('SYRJ')
-ot.remove_language_ot ('SYRN')
-ot.add_language ('und-Syre', 'SYRE')
-ot.add_language ('und-Syrj', 'SYRJ')
-ot.add_language ('und-Syrn', 'SYRN')
-
-bcp_47.names['xst'] = "Silt'e"
-bcp_47.scopes['xst'] = ' (retired code)'
-bcp_47.macrolanguages['xst'] = {'stv', 'wle'}
-
-ot.add_language ('xwo', 'TOD')
-
-ot.remove_language_ot ('ZHH')
-ot.remove_language_ot ('ZHP')
-ot.remove_language_ot ('ZHT')
-ot.remove_language_ot ('ZHTM')
-bcp_47.macrolanguages['zh'].remove ('lzh')
-bcp_47.macrolanguages['zh'].remove ('yue')
-ot.add_language ('zh-Hant-MO', 'ZHH')
-ot.add_language ('zh-Hant-MO', 'ZHTM')
-ot.add_language ('zh-Hant-HK', 'ZHH')
-ot.add_language ('zh-Hans', 'ZHS')
-ot.add_language ('zh-Hant', 'ZHT')
-ot.add_language ('zh-HK', 'ZHH')
-ot.add_language ('zh-MO', 'ZHH')
-ot.add_language ('zh-MO', 'ZHTM')
-ot.add_language ('zh-TW', 'ZHT')
-ot.add_language ('lzh', 'ZHT')
-ot.add_language ('lzh-Hans', 'ZHS')
-ot.add_language ('yue', 'ZHH')
-ot.add_language ('yue-Hans', 'ZHS')
-
-bcp_47.macrolanguages['zom'] = {'yos'}
-
-def rank_delta (bcp_47, ot):
-	"""Return a delta to apply to a BCP 47 tag's rank.
-
-	Most OpenType tags have a constant rank, but a few have ranks that
-	depend on the BCP 47 tag.
-
-	Args:
-		bcp_47 (str): A BCP 47 tag.
-		ot (str): An OpenType tag to.
-
-	Returns:
-		A number to add to ``ot``'s rank when sorting ``bcp_47``'s
-		OpenType equivalents.
-	"""
-	if bcp_47 == 'ak' and ot == 'AKA':
-		return -1
-	if bcp_47 == 'tw' and ot == 'TWI':
-		return -1
-	return 0
-
-disambiguation = {
-	'ALT': 'alt',
-	'ARK': 'rki',
-	'ATH': 'ath',
-	'BHI': 'bhb',
-	'BLN': 'bjt',
-	'BTI': 'beb',
-	'CCHN': 'cco',
-	'CMR': 'swb',
-	'CPP': 'crp',
-	'CRR': 'crx',
-	'DUJ': 'dwu',
-	'ECR': 'crj',
-	'HAL': 'cfm',
-	'HND': 'hnd',
-	'HYE': 'hyw',
-	'KIS': 'kqs',
-	'KUI': 'uki',
-	'LRC': 'bqi',
-	'NDB': 'nd',
-	'NIS': 'njz',
-	'PLG': 'pce',
-	'PRO': 'pro',
-	'QIN': 'bgr',
-	'QUH': 'quh',
-	'QVI': 'qvi',
-	'QWH': 'qwh',
-	'SIG': 'stv',
-	'SRB': 'sr',
-	'SXT': 'xnj',
-	'ZHH': 'zh-HK',
-	'ZHS': 'zh-Hans',
-	'ZHT': 'zh-Hant',
-	'ZHTM': 'zh-MO',
-}
-
-ot.inherit_from_macrolanguages ()
-bcp_47.remove_extra_macrolanguages ()
-ot.inherit_from_macrolanguages ()
-ot.names[DEFAULT_LANGUAGE_SYSTEM] = '*/'
-ot.ranks[DEFAULT_LANGUAGE_SYSTEM] = max (ot.ranks.values ()) + 1
-for tricky_ot_tag in filter (lambda tag: re.match ('[A-Z]{3}$', tag), ot.names):
-	possible_bcp_47_tag = tricky_ot_tag.lower ()
-	if possible_bcp_47_tag in bcp_47.names and not ot.from_bcp_47[possible_bcp_47_tag]:
-		ot.add_language (possible_bcp_47_tag, DEFAULT_LANGUAGE_SYSTEM)
-		bcp_47.macrolanguages[possible_bcp_47_tag] = set ()
-ot.sort_languages ()
-
-print ('/* == Start of generated table == */')
-print ('/*')
-print (' * The following table is generated by running:')
-print (' *')
-print (' *   %s languagetags language-subtag-registry' % sys.argv[0])
-print (' *')
-print (' * on files with these headers:')
-print (' *')
-print (' * %s' % ot.header.strip ())
-print (' * %s' % bcp_47.header)
-print (' */')
-print ()
-print ('#ifndef HB_OT_TAG_TABLE_HH')
-print ('#define HB_OT_TAG_TABLE_HH')
-print ()
-
-def hb_tag (tag):
-	"""Convert a tag to ``HB_TAG`` form.
-
-	Args:
-		tag (str): An OpenType tag.
-
-	Returns:
-		A snippet of C++ representing ``tag``.
-	"""
-	if tag == DEFAULT_LANGUAGE_SYSTEM:
-		return 'HB_TAG_NONE\t       '
-	return "HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
-
-def get_variant_set (name):
-	"""Return a set of variant language names from a name.
-
-	Args:
-		name (str): A list of language names from the BCP 47 registry,
-			joined on ``'\\n'``.
-
-	Returns:
-		A set of normalized language names.
-	"""
-	return set (unicodedata.normalize ('NFD', n.replace ('\u2019', "'"))
-			.encode ('ASCII', 'ignore')
-			.strip ()
-			for n in re.split ('[\n(),]', name) if n)
-
-def language_name_intersection (a, b):
-	"""Return the names in common between two language names.
-
-	Args:
-		a (str): A list of language names from the BCP 47 registry,
-			joined on ``'\\n'``.
-		b (str): A list of language names from the BCP 47 registry,
-			joined on ``'\\n'``.
-
-	Returns:
-		The normalized language names shared by ``a`` and ``b``.
-	"""
-	return get_variant_set (a).intersection (get_variant_set (b))
-
-def get_matching_language_name (intersection, candidates):
-	return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c))))
-
-def same_tag (bcp_47_tag, ot_tags):
-	return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
-
-for language_len in (2, 3):
-	if language_len == 3:
-		print ('#ifndef HB_NO_LANGUAGE_LONG')
-	print ('static const LangTag ot_languages%d[] = {' % language_len)
-	for language, tags in sorted (ot.from_bcp_47.items ()):
-		if language == '' or '-' in language:
-			continue
-		if len(language) != language_len: continue
-		commented_out = same_tag (language, tags)
-		for i, tag in enumerate (tags, start=1):
-			print ('%s{%s,\t%s},' % ('/*' if commented_out else '  ', hb_tag (language), hb_tag (tag)), end='')
-			if commented_out:
-				print ('*/', end='')
-			print ('\t/* ', end='')
-			bcp_47_name = bcp_47.names.get (language, '')
-			bcp_47_name_candidates = bcp_47_name.split ('\n')
-			ot_name = ot.names[tag]
-			scope = bcp_47.scopes.get (language, '')
-			if tag == DEFAULT_LANGUAGE_SYSTEM:
-				write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
-			else:
-				intersection = language_name_intersection (bcp_47_name, ot_name)
-				if not intersection:
-					write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
-				else:
-					name = get_matching_language_name (intersection, bcp_47_name_candidates)
-					bcp_47.names[language] = name
-					write ('%s%s' % (name if len (name) > len (ot_name) else ot_name, scope))
-			print (' */')
-	print ('};')
-	if language_len == 3:
-		print ('#endif')
-	print ()
-
-print ('/**')
-print (' * hb_ot_tags_from_complex_language:')
-print (' * @lang_str: a BCP 47 language tag to convert.')
-print (' * @limit: a pointer to the end of the substring of @lang_str to consider for')
-print (' * conversion.')
-print (' * @count: maximum number of language tags to retrieve (IN) and actual number of')
-print (' * language tags retrieved (OUT). If no tags are retrieved, it is not modified.')
-print (' * @tags: array of size at least @language_count to store the language tag')
-print (' * results')
-print (' *')
-print (' * Converts a multi-subtag BCP 47 language tag to language tags.')
-print (' *')
-print (' * Return value: Whether any language systems were retrieved.')
-print (' **/')
-print ('static inline bool')
-print ('hb_ot_tags_from_complex_language (const char   *lang_str,')
-print ('\t\t\t\t  const char   *limit,')
-print ('\t\t\t\t  unsigned int *count /* IN/OUT */,')
-print ('\t\t\t\t  hb_tag_t     *tags /* OUT */)')
-print ('{')
-
-def print_subtag_matches (subtag, string, new_line):
-	if subtag:
-		if new_line:
-			print ()
-			print ('\t&& ', end='')
-		print ('subtag_matches (%s, limit, "-%s", %i)' % (string, subtag, 1 + len (subtag)), end='')
-
-complex_tags = collections.defaultdict (list)
-for initial, group in itertools.groupby ((lt_tags for lt_tags in [
-			(LanguageTag (language), tags)
-			for language, tags in sorted (ot.from_bcp_47.items (),
-				key=lambda i: (-len (i[0]), i[0]))
-		] if lt_tags[0].is_complex ()),
-		key=lambda lt_tags: lt_tags[0].get_group ()):
-	complex_tags[initial] += group
-
-# Calculate the min length of the subtags outside the switch
-min_subtag_len = 100
-for initial, items in sorted (complex_tags.items ()):
-	if initial != 'und':
-		continue
-	for lt, tags in items:
-		if not tags:
-			continue
-		subtag_len = 0
-		subtag_len += 1 + len (lt.script) if lt.script is not None else 0
-		subtag_len += 1 + len (lt.region) if lt.region is not None else 0
-		subtag_len += 1 + len (lt.variant) if lt.variant is not None else 0
-		min_subtag_len = min(subtag_len, min_subtag_len)
-
-print ('  if (limit - lang_str >= %d)' % (min_subtag_len + 2))
-print ('  {')
-print ("    const char *p = strchr (lang_str, '-');")
-print ("    if (!p || p >= limit || limit - p < %i) goto out;" % min_subtag_len)
-for initial, items in sorted (complex_tags.items ()):
-	if initial != 'und':
-		continue
-	for lt, tags in items:
-		if not tags:
-			continue
-		if lt.variant in bcp_47.prefixes:
-			expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language,
-					'%s is not a valid prefix of %s' % (lt.language, lt.variant))
-		print ('    if (', end='')
-		print_subtag_matches (lt.script, 'p', False)
-		print_subtag_matches (lt.region, 'p', False)
-		print_subtag_matches (lt.variant, 'p', False)
-		print (')')
-		print ('    {')
-		write ('      /* %s */' % bcp_47.get_name (lt))
-		print ()
-		if len (tags) == 1:
-			write ('      tags[0] = %s;  /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
-			print ()
-			print ('      *count = 1;')
-		else:
-			print ('    hb_tag_t possible_tags[] = {')
-			for tag in tags:
-				write ('      %s,  /* %s */' % (hb_tag (tag), ot.names[tag]))
-				print ()
-			print ('      };')
-			print ('      for (i = 0; i < %s && i < *count; i++)' % len (tags))
-			print ('\ttags[i] = possible_tags[i];')
-			print ('      *count = i;')
-		print ('      return true;')
-		print ('    }')
-print ('  }')
-print ('out:')
-
-print ('  switch (lang_str[0])')
-print ('  {')
-for initial, items in sorted (complex_tags.items ()):
-	if initial == 'und':
-		continue
-	print ("  case '%s':" % initial)
-	for lt, tags in items:
-		if not tags:
-			continue
-		print ('    if (', end='')
-		script = lt.script
-		region = lt.region
-		if lt.grandfathered:
-			print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='')
-		else:
-			string_literal = lt.language[1:] + '-'
-			if script:
-				string_literal += script
-				script = None
-				if region:
-					string_literal += '-' + region
-					region = None
-			if string_literal[-1] == '-':
-				print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='')
-			else:
-				print ('lang_matches (&lang_str[1], limit, "%s", %i)' % (string_literal, len (string_literal)), end='')
-		print_subtag_matches (script, 'lang_str', True)
-		print_subtag_matches (region, 'lang_str', True)
-		print_subtag_matches (lt.variant, 'lang_str', True)
-		print (')')
-		print ('    {')
-		write ('      /* %s */' % bcp_47.get_name (lt))
-		print ()
-		if len (tags) == 1:
-			write ('      tags[0] = %s;  /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
-			print ()
-			print ('      *count = 1;')
-		else:
-			print ('      unsigned int i;')
-			print ('      hb_tag_t possible_tags[] = {')
-			for tag in tags:
-				write ('\t%s,  /* %s */' % (hb_tag (tag), ot.names[tag]))
-				print ()
-			print ('      };')
-			print ('      for (i = 0; i < %s && i < *count; i++)' % len (tags))
-			print ('\ttags[i] = possible_tags[i];')
-			print ('      *count = i;')
-		print ('      return true;')
-		print ('    }')
-	print ('    break;')
-
-print ('  }')
-print ('  return false;')
-print ('}')
-print ()
-print ('/**')
-print (' * hb_ot_ambiguous_tag_to_language')
-print (' * @tag: A language tag.')
-print (' *')
-print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to')
-print (' * many language tags) and the best tag is not the alphabetically first, or if')
-print (' * the best tag consists of multiple subtags, or if the best tag does not appear')
-print (' * in #ot_languages.')
-print (' *')
-print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
-print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
-print (' **/')
-print ('static inline hb_language_t')
-print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)')
-print ('{')
-print ('  switch (tag)')
-print ('  {')
-
-def verify_disambiguation_dict ():
-	"""Verify and normalize ``disambiguation``.
-
-	``disambiguation`` is a map of ambiguous OpenType language system
-	tags to the particular BCP 47 tags they correspond to. This function
-	checks that all its keys really are ambiguous and that each key's
-	value is valid for that key. It checks that no ambiguous tag is
-	missing, except when it can figure out which BCP 47 tag is the best
-	by itself.
-
-	It modifies ``disambiguation`` to remove keys whose values are the
-	same as those that the fallback would return anyway, and to add
-	ambiguous keys whose disambiguations it determined automatically.
-
-	Raises:
-		AssertionError: Verification failed.
-	"""
-	global bcp_47
-	global disambiguation
-	global ot
-	for ot_tag, bcp_47_tags in ot.to_bcp_47.items ():
-		if ot_tag == DEFAULT_LANGUAGE_SYSTEM:
-			primary_tags = []
-		else:
-			primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag)
-		if len (primary_tags) == 1:
-			expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag)
-			if '-' in primary_tags[0]:
-				disambiguation[ot_tag] = primary_tags[0]
-			else:
-				first_tag = sorted (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t))[0]
-				if primary_tags[0] != first_tag:
-					disambiguation[ot_tag] = primary_tags[0]
-		elif len (primary_tags) == 0:
-			expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag)
-		else:
-			original_languages = [t for t in primary_tags if t in ot.from_bcp_47_uninherited and 'retired code' not in bcp_47.scopes.get (t, '')]
-			if len (original_languages) == 1:
-				macrolanguages = original_languages
-			else:
-				macrolanguages = [t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]']
-			if len (macrolanguages) != 1:
-				macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [collection]')
-			if len (macrolanguages) != 1:
-				macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, ''))
-			if len (macrolanguages) != 1:
-				expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages)))
-				expect (disambiguation[ot_tag] in bcp_47_tags,
-						'%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
-			elif ot_tag not in disambiguation:
-				disambiguation[ot_tag] = macrolanguages[0]
-			different_bcp_47_tags = sorted (t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t)))
-			if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0] and '-' not in disambiguation[ot_tag]:
-				del disambiguation[ot_tag]
-	for ot_tag in disambiguation.keys ():
-		expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
-
-verify_disambiguation_dict ()
-for ot_tag, bcp_47_tag in sorted (disambiguation.items ()):
-	write ('  case %s:  /* %s */' % (hb_tag (ot_tag), ot.names[ot_tag]))
-	print ()
-	write ('    return hb_language_from_string (\"%s\", -1);  /* %s */' % (bcp_47_tag, bcp_47.get_name (LanguageTag (bcp_47_tag))))
-	print ()
-
-print ('  default:')
-print ('    return HB_LANGUAGE_INVALID;')
-print ('  }')
-print ('}')
-
-print ()
-print ('#endif /* HB_OT_TAG_TABLE_HH */')
-print ()
-print ('/* == End of generated table == */')
-
+#!/usr/bin/env python3
+
+"""Generator of the mapping from OpenType tags to BCP 47 tags and vice
+versa.
+
+It creates a ``const LangTag[]``, matching the tags from the OpenType
+languages system tag list to the language subtags of the BCP 47 language
+subtag registry, with some manual adjustments. The mappings are
+supplemented with macrolanguages' sublanguages and retired codes'
+replacements, according to BCP 47 and some manual additions where BCP 47
+omits a retired code entirely.
+
+Also generated is a function, ``hb_ot_ambiguous_tag_to_language``,
+intended for use by ``hb_ot_tag_to_language``. It maps OpenType tags
+back to BCP 47 tags. Ambiguous OpenType tags (those that correspond to
+multiple BCP 47 tags) are listed here, except when the alphabetically
+first BCP 47 tag happens to be the chosen disambiguated tag. In that
+case, the fallback behavior will choose the right tag anyway.
+
+usage: ./gen-tag-table.py languagetags language-subtag-registry
+
+Input files:
+* https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
+* https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
+"""
+
+import collections
+import html
+from html.parser import HTMLParser
+import itertools
+import re
+import sys
+import unicodedata
+
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
+
+def expect (condition, message=None):
+	if not condition:
+		if message is None:
+			raise AssertionError
+		raise AssertionError (message)
+
+def write (s):
+	sys.stdout.flush ()
+	sys.stdout.buffer.write (s.encode ('utf-8'))
+
+DEFAULT_LANGUAGE_SYSTEM = ''
+
+# from https://www-01.sil.org/iso639-3/iso-639-3.tab
+ISO_639_3_TO_1 = {
+	'aar': 'aa',
+	'abk': 'ab',
+	'afr': 'af',
+	'aka': 'ak',
+	'amh': 'am',
+	'ara': 'ar',
+	'arg': 'an',
+	'asm': 'as',
+	'ava': 'av',
+	'ave': 'ae',
+	'aym': 'ay',
+	'aze': 'az',
+	'bak': 'ba',
+	'bam': 'bm',
+	'bel': 'be',
+	'ben': 'bn',
+	'bis': 'bi',
+	'bod': 'bo',
+	'bos': 'bs',
+	'bre': 'br',
+	'bul': 'bg',
+	'cat': 'ca',
+	'ces': 'cs',
+	'cha': 'ch',
+	'che': 'ce',
+	'chu': 'cu',
+	'chv': 'cv',
+	'cor': 'kw',
+	'cos': 'co',
+	'cre': 'cr',
+	'cym': 'cy',
+	'dan': 'da',
+	'deu': 'de',
+	'div': 'dv',
+	'dzo': 'dz',
+	'ell': 'el',
+	'eng': 'en',
+	'epo': 'eo',
+	'est': 'et',
+	'eus': 'eu',
+	'ewe': 'ee',
+	'fao': 'fo',
+	'fas': 'fa',
+	'fij': 'fj',
+	'fin': 'fi',
+	'fra': 'fr',
+	'fry': 'fy',
+	'ful': 'ff',
+	'gla': 'gd',
+	'gle': 'ga',
+	'glg': 'gl',
+	'glv': 'gv',
+	'grn': 'gn',
+	'guj': 'gu',
+	'hat': 'ht',
+	'hau': 'ha',
+	'hbs': 'sh',
+	'heb': 'he',
+	'her': 'hz',
+	'hin': 'hi',
+	'hmo': 'ho',
+	'hrv': 'hr',
+	'hun': 'hu',
+	'hye': 'hy',
+	'ibo': 'ig',
+	'ido': 'io',
+	'iii': 'ii',
+	'iku': 'iu',
+	'ile': 'ie',
+	'ina': 'ia',
+	'ind': 'id',
+	'ipk': 'ik',
+	'isl': 'is',
+	'ita': 'it',
+	'jav': 'jv',
+	'jpn': 'ja',
+	'kal': 'kl',
+	'kan': 'kn',
+	'kas': 'ks',
+	'kat': 'ka',
+	'kau': 'kr',
+	'kaz': 'kk',
+	'khm': 'km',
+	'kik': 'ki',
+	'kin': 'rw',
+	'kir': 'ky',
+	'kom': 'kv',
+	'kon': 'kg',
+	'kor': 'ko',
+	'kua': 'kj',
+	'kur': 'ku',
+	'lao': 'lo',
+	'lat': 'la',
+	'lav': 'lv',
+	'lim': 'li',
+	'lin': 'ln',
+	'lit': 'lt',
+	'ltz': 'lb',
+	'lub': 'lu',
+	'lug': 'lg',
+	'mah': 'mh',
+	'mal': 'ml',
+	'mar': 'mr',
+	'mkd': 'mk',
+	'mlg': 'mg',
+	'mlt': 'mt',
+	'mol': 'mo',
+	'mon': 'mn',
+	'mri': 'mi',
+	'msa': 'ms',
+	'mya': 'my',
+	'nau': 'na',
+	'nav': 'nv',
+	'nbl': 'nr',
+	'nde': 'nd',
+	'ndo': 'ng',
+	'nep': 'ne',
+	'nld': 'nl',
+	'nno': 'nn',
+	'nob': 'nb',
+	'nor': 'no',
+	'nya': 'ny',
+	'oci': 'oc',
+	'oji': 'oj',
+	'ori': 'or',
+	'orm': 'om',
+	'oss': 'os',
+	'pan': 'pa',
+	'pli': 'pi',
+	'pol': 'pl',
+	'por': 'pt',
+	'pus': 'ps',
+	'que': 'qu',
+	'roh': 'rm',
+	'ron': 'ro',
+	'run': 'rn',
+	'rus': 'ru',
+	'sag': 'sg',
+	'san': 'sa',
+	'sin': 'si',
+	'slk': 'sk',
+	'slv': 'sl',
+	'sme': 'se',
+	'smo': 'sm',
+	'sna': 'sn',
+	'snd': 'sd',
+	'som': 'so',
+	'sot': 'st',
+	'spa': 'es',
+	'sqi': 'sq',
+	'srd': 'sc',
+	'srp': 'sr',
+	'ssw': 'ss',
+	'sun': 'su',
+	'swa': 'sw',
+	'swe': 'sv',
+	'tah': 'ty',
+	'tam': 'ta',
+	'tat': 'tt',
+	'tel': 'te',
+	'tgk': 'tg',
+	'tgl': 'tl',
+	'tha': 'th',
+	'tir': 'ti',
+	'ton': 'to',
+	'tsn': 'tn',
+	'tso': 'ts',
+	'tuk': 'tk',
+	'tur': 'tr',
+	'twi': 'tw',
+	'uig': 'ug',
+	'ukr': 'uk',
+	'urd': 'r',
+	'uzb': 'uz',
+	'ven': 've',
+	'vie': 'vi',
+	'vol': 'vo',
+	'wln': 'wa',
+	'wol': 'wo',
+	'xho': 'xh',
+	'yid': 'yi',
+	'yor': 'yo',
+	'zha': 'za',
+	'zho': 'zh',
+	'zul': 'zu',
+}
+
+class LanguageTag (object):
+	"""A BCP 47 language tag.
+
+	Attributes:
+		subtags (List[str]): The list of subtags in this tag.
+		grandfathered (bool): Whether this tag is grandfathered. If
+			``true``, the entire lowercased tag is the ``language``
+			and the other subtag fields are empty.
+		language (str): The language subtag.
+		script (str): The script subtag.
+		region (str): The region subtag.
+		variant (str): The variant subtag.
+
+	Args:
+		tag (str): A BCP 47 language tag.
+
+	"""
+	def __init__ (self, tag):
+		global bcp_47
+		self.subtags = tag.lower ().split ('-')
+		self.grandfathered = tag.lower () in bcp_47.grandfathered
+		if self.grandfathered:
+			self.language = tag.lower ()
+			self.script = ''
+			self.region = ''
+			self.variant = ''
+		else:
+			self.language = self.subtags[0]
+			self.script = self._find_first (lambda s: len (s) == 4 and s[0] > '9', self.subtags)
+			self.region = self._find_first (lambda s: len (s) == 2 and s[0] > '9' or len (s) == 3 and s[0] <= '9', self.subtags[1:])
+			self.variant = self._find_first (lambda s: len (s) > 4 or len (s) == 4 and s[0] <= '9', self.subtags)
+
+	def __str__(self):
+		return '-'.join(self.subtags)
+
+	def __repr__ (self):
+		return 'LanguageTag(%r)' % str(self)
+
+	@staticmethod
+	def _find_first (function, sequence):
+		try:
+			return next (iter (filter (function, sequence)))
+		except StopIteration:
+			return None
+
+	def is_complex (self):
+		"""Return whether this tag is too complex to represent as a
+		``LangTag`` in the generated code.
+
+		Complex tags need to be handled in
+		``hb_ot_tags_from_complex_language``.
+
+		Returns:
+			Whether this tag is complex.
+		"""
+		return not (len (self.subtags) == 1
+			or self.grandfathered
+			and len (self.subtags[1]) != 3
+			and ot.from_bcp_47[self.subtags[0]] == ot.from_bcp_47[self.language])
+
+	def get_group (self):
+		"""Return the group into which this tag should be categorized in
+		``hb_ot_tags_from_complex_language``.
+
+		The group is the first letter of the tag, or ``'und'`` if this tag
+		should not be matched in a ``switch`` statement in the generated
+		code.
+
+		Returns:
+			This tag's group.
+		"""
+		return ('und'
+			if (self.language == 'und'
+				or self.variant in bcp_47.prefixes and len (bcp_47.prefixes[self.variant]) == 1)
+			else self.language[0])
+
+class OpenTypeRegistryParser (HTMLParser):
+	"""A parser for the OpenType language system tag registry.
+
+	Attributes:
+		header (str): The "last updated" line of the registry.
+		names (Mapping[str, str]): A map of language system tags to the
+			names they are given in the registry.
+		ranks (DefaultDict[str, int]): A map of language system tags to
+			numbers. If a single BCP 47 tag corresponds to multiple
+			OpenType tags, the tags are ordered in increasing order by
+			rank. The rank is based on the number of BCP 47 tags
+			associated with a tag, though it may be manually modified.
+		to_bcp_47 (DefaultDict[str, AbstractSet[str]]): A map of
+			OpenType language system tags to sets of BCP 47 tags.
+		from_bcp_47 (DefaultDict[str, AbstractSet[str]]): ``to_bcp_47``
+			inverted. Its values start as unsorted sets;
+			``sort_languages`` converts them to sorted lists.
+		from_bcp_47_uninherited (Optional[Dict[str, AbstractSet[str]]]):
+			A copy of ``from_bcp_47``. It starts as ``None`` and is
+			populated at the beginning of the first call to
+			``inherit_from_macrolanguages``.
+
+	"""
+	def __init__ (self):
+		HTMLParser.__init__ (self)
+		self.header = ''
+		self.names = {}
+		self.ranks = collections.defaultdict (int)
+		self.to_bcp_47 = collections.defaultdict (set)
+		self.from_bcp_47 = collections.defaultdict (set)
+		self.from_bcp_47_uninherited = None
+		# Whether the parser is in a <td> element
+		self._td = False
+		# Whether the parser is after a <br> element within the current <tr> element
+		self._br = False
+		# The text of the <td> elements of the current <tr> element.
+		self._current_tr = []
+
+	def handle_starttag (self, tag, attrs):
+		if tag == 'br':
+			self._br = True
+		elif tag == 'meta':
+			for attr, value in attrs:
+				if attr == 'name' and value == 'updated_at':
+					self.header = self.get_starttag_text ()
+					break
+		elif tag == 'td':
+			self._td = True
+			self._current_tr.append ('')
+		elif tag == 'tr':
+			self._br = False
+			self._current_tr = []
+
+	def handle_endtag (self, tag):
+		if tag == 'td':
+			self._td = False
+		elif tag == 'tr' and self._current_tr:
+			expect (2 <= len (self._current_tr) <= 3)
+			name = self._current_tr[0].strip ()
+			tag = self._current_tr[1].strip ("\t\n\v\f\r '")
+			rank = 0
+			if len (tag) > 4:
+				expect (tag.endswith (' (deprecated)'), 'ill-formed OpenType tag: %s' % tag)
+				name += ' (deprecated)'
+				tag = tag.split (' ')[0]
+				rank = 1
+			self.names[tag] = re.sub (' languages$', '', name)
+			if not self._current_tr[2]:
+				return
+			iso_codes = self._current_tr[2].strip ()
+			self.to_bcp_47[tag].update (ISO_639_3_TO_1.get (code, code) for code in iso_codes.replace (' ', '').split (','))
+			rank += 2 * len (self.to_bcp_47[tag])
+			self.ranks[tag] = rank
+
+	def handle_data (self, data):
+		if self._td and not self._br:
+			self._current_tr[-1] += data
+
+	def handle_charref (self, name):
+		self.handle_data (html.unescape ('&#%s;' % name))
+
+	def handle_entityref (self, name):
+		self.handle_data (html.unescape ('&%s;' % name))
+
+	def parse (self, filename):
+		"""Parse the OpenType language system tag registry.
+
+		Args:
+			filename (str): The file name of the registry.
+		"""
+		with open (filename, encoding='utf-8') as f:
+			self.feed (f.read ())
+		expect (self.header)
+		for tag, iso_codes in self.to_bcp_47.items ():
+			for iso_code in iso_codes:
+				self.from_bcp_47[iso_code].add (tag)
+
+	def add_language (self, bcp_47_tag, ot_tag):
+		"""Add a language as if it were in the registry.
+
+		Args:
+			bcp_47_tag (str): A BCP 47 tag. If the tag is more than just
+				a language subtag, and if the language subtag is a
+				macrolanguage, then new languages are added corresponding
+				to the macrolanguages' individual languages with the
+				remainder of the tag appended.
+			ot_tag (str): An OpenType language system tag.
+		"""
+		global bcp_47
+		self.to_bcp_47[ot_tag].add (bcp_47_tag)
+		self.from_bcp_47[bcp_47_tag].add (ot_tag)
+		if bcp_47_tag.lower () not in bcp_47.grandfathered:
+			try:
+				[macrolanguage, suffix] = bcp_47_tag.split ('-', 1)
+				if macrolanguage in bcp_47.macrolanguages:
+					s = set ()
+					for language in bcp_47.macrolanguages[macrolanguage]:
+						if language.lower () not in bcp_47.grandfathered:
+							s.add ('%s-%s' % (language, suffix))
+					bcp_47.macrolanguages['%s-%s' % (macrolanguage, suffix)] = s
+			except ValueError:
+				pass
+
+	@staticmethod
+	def _remove_language (tag_1, dict_1, dict_2):
+		for tag_2 in dict_1.pop (tag_1):
+			dict_2[tag_2].remove (tag_1)
+			if not dict_2[tag_2]:
+				del dict_2[tag_2]
+
+	def remove_language_ot (self, ot_tag):
+		"""Remove an OpenType tag from the registry.
+
+		Args:
+			ot_tag (str): An OpenType tag.
+		"""
+		self._remove_language (ot_tag, self.to_bcp_47, self.from_bcp_47)
+
+	def remove_language_bcp_47 (self, bcp_47_tag):
+		"""Remove a BCP 47 tag from the registry.
+
+		Args:
+			bcp_47_tag (str): A BCP 47 tag.
+		"""
+		self._remove_language (bcp_47_tag, self.from_bcp_47, self.to_bcp_47)
+
+	def inherit_from_macrolanguages (self):
+		"""Copy mappings from macrolanguages to individual languages.
+
+		If a BCP 47 tag for an individual mapping has no OpenType
+		mapping but its macrolanguage does, the mapping is copied to
+		the individual language. For example, als (Tosk Albanian) has no
+		explicit mapping, so it inherits from sq (Albanian) the mapping
+		to SQI.
+
+		However, if an OpenType tag maps to a BCP 47 macrolanguage and
+		some but not all of its individual languages, the mapping is not
+		inherited from the macrolanguage to the missing individual
+		languages. For example, INUK (Nunavik Inuktitut) is mapped to
+		ike (Eastern Canadian Inuktitut) and iu (Inuktitut) but not to
+		ikt (Inuinnaqtun, which is an individual language of iu), so
+		this method does not add a mapping from ikt to INUK.
+
+		If a BCP 47 tag for a macrolanguage has no OpenType mapping but
+		some of its individual languages do, their mappings are copied
+		to the macrolanguage.
+		"""
+		global bcp_47
+		first_time = self.from_bcp_47_uninherited is None
+		if first_time:
+			self.from_bcp_47_uninherited = dict (self.from_bcp_47)
+		for macrolanguage, languages in dict (bcp_47.macrolanguages).items ():
+			ot_macrolanguages = {
+				ot_macrolanguage for ot_macrolanguage in self.from_bcp_47_uninherited.get (macrolanguage, set ())
+			}
+			blocked_ot_macrolanguages = set ()
+			if 'retired code' not in bcp_47.scopes.get (macrolanguage, ''):
+				for ot_macrolanguage in ot_macrolanguages:
+					round_trip_macrolanguages = {
+						l for l in self.to_bcp_47[ot_macrolanguage]
+						if 'retired code' not in bcp_47.scopes.get (l, '')
+					}
+					round_trip_languages = {
+						l for l in languages
+						if 'retired code' not in bcp_47.scopes.get (l, '')
+					}
+					intersection = round_trip_macrolanguages & round_trip_languages
+					if intersection and intersection != round_trip_languages:
+						blocked_ot_macrolanguages.add (ot_macrolanguage)
+			if ot_macrolanguages:
+				for ot_macrolanguage in ot_macrolanguages:
+					if ot_macrolanguage not in blocked_ot_macrolanguages:
+						for language in languages:
+							self.add_language (language, ot_macrolanguage)
+							if not blocked_ot_macrolanguages:
+								self.ranks[ot_macrolanguage] += 1
+			elif first_time:
+				for language in languages:
+					if language in self.from_bcp_47_uninherited:
+						ot_macrolanguages |= self.from_bcp_47_uninherited[language]
+					else:
+						ot_macrolanguages.clear ()
+					if not ot_macrolanguages:
+						break
+				for ot_macrolanguage in ot_macrolanguages:
+					self.add_language (macrolanguage, ot_macrolanguage)
+
+	def sort_languages (self):
+		"""Sort the values of ``from_bcp_47`` in ascending rank order."""
+		for language, tags in self.from_bcp_47.items ():
+			self.from_bcp_47[language] = sorted (tags,
+					key=lambda t: (self.ranks[t] + rank_delta (language, t), t))
+
+ot = OpenTypeRegistryParser ()
+
+class BCP47Parser (object):
+	"""A parser for the BCP 47 subtag registry.
+
+	Attributes:
+		header (str): The "File-Date" line of the registry.
+		names (Mapping[str, str]): A map of subtags to the names they
+			are given in the registry. Each value is a
+			``'\\n'``-separated list of names.
+		scopes (Mapping[str, str]): A map of language subtags to strings
+			suffixed to language names, including suffixes to explain
+			language scopes.
+		macrolanguages (DefaultDict[str, AbstractSet[str]]): A map of
+			language subtags to the sets of language subtags which
+			inherit from them. See
+			``OpenTypeRegistryParser.inherit_from_macrolanguages``.
+		prefixes (DefaultDict[str, AbstractSet[str]]): A map of variant
+			subtags to their prefixes.
+		grandfathered (AbstractSet[str]): The set of grandfathered tags,
+			normalized to lowercase.
+
+	"""
+	def __init__ (self):
+		self.header = ''
+		self.names = {}
+		self.scopes = {}
+		self.macrolanguages = collections.defaultdict (set)
+		self.prefixes = collections.defaultdict (set)
+		self.grandfathered = set ()
+
+	def parse (self, filename):
+		"""Parse the BCP 47 subtag registry.
+
+		Args:
+			filename (str): The file name of the registry.
+		"""
+		with open (filename, encoding='utf-8') as f:
+			subtag_type = None
+			subtag = None
+			deprecated = False
+			has_preferred_value = False
+			line_buffer = ''
+			for line in itertools.chain (f, ['']):
+				line = line.rstrip ()
+				if line.startswith (' '):
+					line_buffer += line[1:]
+					continue
+				line, line_buffer = line_buffer, line
+				if line.startswith ('Type: '):
+					subtag_type = line.split (' ')[1]
+					deprecated = False
+					has_preferred_value = False
+				elif line.startswith ('Subtag: ') or line.startswith ('Tag: '):
+					subtag = line.split (' ')[1]
+					if subtag_type == 'grandfathered':
+						self.grandfathered.add (subtag.lower ())
+				elif line.startswith ('Description: '):
+					description = line.split (' ', 1)[1].replace (' (individual language)', '')
+					description = re.sub (' (\(family\)|\((individual |macro)language\)|languages)$', '',
+							description)
+					if subtag in self.names:
+						self.names[subtag] += '\n' + description
+					else:
+						self.names[subtag] = description
+				elif subtag_type == 'language' or subtag_type == 'grandfathered':
+					if line.startswith ('Scope: '):
+						scope = line.split (' ')[1]
+						if scope == 'macrolanguage':
+							scope = ' [macrolanguage]'
+						elif scope == 'collection':
+							scope = ' [collection]'
+						else:
+							continue
+						self.scopes[subtag] = scope
+					elif line.startswith ('Deprecated: '):
+						self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
+						deprecated = True
+					elif deprecated and line.startswith ('Comments: see '):
+						# If a subtag is split into multiple replacement subtags,
+						# it essentially represents a macrolanguage.
+						for language in line.replace (',', '').split (' ')[2:]:
+							self._add_macrolanguage (subtag, language)
+					elif line.startswith ('Preferred-Value: '):
+						# If a subtag is deprecated in favor of a single replacement subtag,
+						# it is either a dialect or synonym of the preferred subtag. Either
+						# way, it is close enough to the truth to consider the replacement
+						# the macrolanguage of the deprecated language.
+						has_preferred_value = True
+						macrolanguage = line.split (' ')[1]
+						self._add_macrolanguage (macrolanguage, subtag)
+					elif not has_preferred_value and line.startswith ('Macrolanguage: '):
+						self._add_macrolanguage (line.split (' ')[1], subtag)
+				elif subtag_type == 'variant':
+					if line.startswith ('Deprecated: '):
+						self.scopes[subtag] = ' (retired code)' + self.scopes.get (subtag, '')
+					elif line.startswith ('Prefix: '):
+						self.prefixes[subtag].add (line.split (' ')[1])
+				elif line.startswith ('File-Date: '):
+					self.header = line
+		expect (self.header)
+
+	def _add_macrolanguage (self, macrolanguage, language):
+		global ot
+		if language not in ot.from_bcp_47:
+			for l in self.macrolanguages.get (language, set ()):
+				self._add_macrolanguage (macrolanguage, l)
+		if macrolanguage not in ot.from_bcp_47:
+			for ls in list (self.macrolanguages.values ()):
+				if macrolanguage in ls:
+					ls.add (language)
+					return
+		self.macrolanguages[macrolanguage].add (language)
+
+	def remove_extra_macrolanguages (self):
+		"""Make every language have at most one macrolanguage."""
+		inverted = collections.defaultdict (list)
+		for macrolanguage, languages in self.macrolanguages.items ():
+			for language in languages:
+				inverted[language].append (macrolanguage)
+		for language, macrolanguages in inverted.items ():
+			if len (macrolanguages) > 1:
+				macrolanguages.sort (key=lambda ml: len (self.macrolanguages[ml]))
+				biggest_macrolanguage = macrolanguages.pop ()
+				for macrolanguage in macrolanguages:
+					self._add_macrolanguage (biggest_macrolanguage, macrolanguage)
+
+	def _get_name_piece (self, subtag):
+		"""Return the first name of a subtag plus its scope suffix.
+
+		Args:
+			subtag (str): A BCP 47 subtag.
+
+		Returns:
+			The name form of ``subtag``.
+		"""
+		return self.names[subtag].split ('\n')[0] + self.scopes.get (subtag, '')
+
+	def get_name (self, lt):
+		"""Return the names of the subtags in a language tag.
+
+		Args:
+			lt (LanguageTag): A BCP 47 language tag.
+
+		Returns:
+			The name form of ``lt``.
+		"""
+		name = self._get_name_piece (lt.language)
+		if lt.script:
+			name += '; ' + self._get_name_piece (lt.script.title ())
+		if lt.region:
+			name += '; ' + self._get_name_piece (lt.region.upper ())
+		if lt.variant:
+			name += '; ' + self._get_name_piece (lt.variant)
+		return name
+
+bcp_47 = BCP47Parser ()
+
+ot.parse (sys.argv[1])
+bcp_47.parse (sys.argv[2])
+
+ot.add_language ('ary', 'MOR')
+
+ot.add_language ('ath', 'ATH')
+
+ot.add_language ('bai', 'BML')
+
+ot.ranks['BAL'] = ot.ranks['KAR'] + 1
+
+ot.add_language ('ber', 'BBR')
+
+ot.remove_language_ot ('PGR')
+ot.add_language ('el-polyton', 'PGR')
+
+bcp_47.macrolanguages['et'] = {'ekk'}
+
+bcp_47.names['flm'] = 'Falam Chin'
+bcp_47.scopes['flm'] = ' (retired code)'
+bcp_47.macrolanguages['flm'] = {'cfm'}
+
+ot.ranks['FNE'] = ot.ranks['TNE'] + 1
+
+ot.add_language ('und-fonipa', 'IPPH')
+
+ot.add_language ('und-fonnapa', 'APPH')
+
+ot.remove_language_ot ('IRT')
+ot.add_language ('ga-Latg', 'IRT')
+
+ot.add_language ('hy-arevmda', 'HYE')
+
+ot.remove_language_ot ('KGE')
+ot.add_language ('und-Geok', 'KGE')
+
+bcp_47.macrolanguages['id'] = {'in'}
+
+bcp_47.macrolanguages['ijo'] = {'ijc'}
+
+ot.add_language ('kht', 'KHN')
+ot.names['KHN'] = ot.names['KHT'] + ' (Microsoft fonts)'
+ot.ranks['KHN'] = ot.ranks['KHT'] + 1
+
+ot.ranks['LCR'] = ot.ranks['MCR'] + 1
+
+ot.names['MAL'] = 'Malayalam Traditional'
+ot.ranks['MLR'] += 1
+
+bcp_47.names['mhv'] = 'Arakanese'
+bcp_47.scopes['mhv'] = ' (retired code)'
+
+ot.add_language ('mnw-TH', 'MONT')
+
+ot.add_language ('no', 'NOR')
+
+ot.add_language ('oc-provenc', 'PRO')
+
+ot.remove_language_ot ('QUZ')
+ot.add_language ('qu', 'QUZ')
+ot.add_language ('qub', 'QWH')
+ot.add_language ('qud', 'QVI')
+ot.add_language ('qug', 'QVI')
+ot.add_language ('qul', 'QUH')
+ot.add_language ('qup', 'QVI')
+ot.add_language ('qur', 'QWH')
+ot.add_language ('qus', 'QUH')
+ot.add_language ('quw', 'QVI')
+ot.add_language ('qux', 'QWH')
+ot.add_language ('qva', 'QWH')
+ot.add_language ('qvh', 'QWH')
+ot.add_language ('qvj', 'QVI')
+ot.add_language ('qvl', 'QWH')
+ot.add_language ('qvm', 'QWH')
+ot.add_language ('qvn', 'QWH')
+ot.add_language ('qvo', 'QVI')
+ot.add_language ('qvp', 'QWH')
+ot.add_language ('qvw', 'QWH')
+ot.add_language ('qvz', 'QVI')
+ot.add_language ('qwa', 'QWH')
+ot.add_language ('qws', 'QWH')
+ot.add_language ('qxa', 'QWH')
+ot.add_language ('qxc', 'QWH')
+ot.add_language ('qxh', 'QWH')
+ot.add_language ('qxl', 'QVI')
+ot.add_language ('qxn', 'QWH')
+ot.add_language ('qxo', 'QWH')
+ot.add_language ('qxr', 'QVI')
+ot.add_language ('qxt', 'QWH')
+ot.add_language ('qxw', 'QWH')
+
+bcp_47.macrolanguages['ro-MD'].add ('mo')
+
+ot.remove_language_ot ('SYRE')
+ot.remove_language_ot ('SYRJ')
+ot.remove_language_ot ('SYRN')
+ot.add_language ('und-Syre', 'SYRE')
+ot.add_language ('und-Syrj', 'SYRJ')
+ot.add_language ('und-Syrn', 'SYRN')
+
+bcp_47.names['xst'] = "Silt'e"
+bcp_47.scopes['xst'] = ' (retired code)'
+bcp_47.macrolanguages['xst'] = {'stv', 'wle'}
+
+ot.add_language ('xwo', 'TOD')
+
+ot.remove_language_ot ('ZHH')
+ot.remove_language_ot ('ZHP')
+ot.remove_language_ot ('ZHT')
+ot.remove_language_ot ('ZHTM')
+bcp_47.macrolanguages['zh'].remove ('lzh')
+bcp_47.macrolanguages['zh'].remove ('yue')
+ot.add_language ('zh-Hant-MO', 'ZHH')
+ot.add_language ('zh-Hant-MO', 'ZHTM')
+ot.add_language ('zh-Hant-HK', 'ZHH')
+ot.add_language ('zh-Hans', 'ZHS')
+ot.add_language ('zh-Hant', 'ZHT')
+ot.add_language ('zh-HK', 'ZHH')
+ot.add_language ('zh-MO', 'ZHH')
+ot.add_language ('zh-MO', 'ZHTM')
+ot.add_language ('zh-TW', 'ZHT')
+ot.add_language ('lzh', 'ZHT')
+ot.add_language ('lzh-Hans', 'ZHS')
+ot.add_language ('yue', 'ZHH')
+ot.add_language ('yue-Hans', 'ZHS')
+
+bcp_47.macrolanguages['zom'] = {'yos'}
+
+def rank_delta (bcp_47, ot):
+	"""Return a delta to apply to a BCP 47 tag's rank.
+
+	Most OpenType tags have a constant rank, but a few have ranks that
+	depend on the BCP 47 tag.
+
+	Args:
+		bcp_47 (str): A BCP 47 tag.
+		ot (str): An OpenType tag to.
+
+	Returns:
+		A number to add to ``ot``'s rank when sorting ``bcp_47``'s
+		OpenType equivalents.
+	"""
+	if bcp_47 == 'ak' and ot == 'AKA':
+		return -1
+	if bcp_47 == 'tw' and ot == 'TWI':
+		return -1
+	return 0
+
+disambiguation = {
+	'ALT': 'alt',
+	'ARK': 'rki',
+	'ATH': 'ath',
+	'BHI': 'bhb',
+	'BLN': 'bjt',
+	'BTI': 'beb',
+	'CCHN': 'cco',
+	'CMR': 'swb',
+	'CPP': 'crp',
+	'CRR': 'crx',
+	'DUJ': 'dwu',
+	'ECR': 'crj',
+	'HAL': 'cfm',
+	'HND': 'hnd',
+	'HYE': 'hyw',
+	'KIS': 'kqs',
+	'KUI': 'uki',
+	'LRC': 'bqi',
+	'NDB': 'nd',
+	'NIS': 'njz',
+	'PLG': 'pce',
+	'PRO': 'pro',
+	'QIN': 'bgr',
+	'QUH': 'quh',
+	'QVI': 'qvi',
+	'QWH': 'qwh',
+	'SIG': 'stv',
+	'SRB': 'sr',
+	'SXT': 'xnj',
+	'ZHH': 'zh-HK',
+	'ZHS': 'zh-Hans',
+	'ZHT': 'zh-Hant',
+	'ZHTM': 'zh-MO',
+}
+
+ot.inherit_from_macrolanguages ()
+bcp_47.remove_extra_macrolanguages ()
+ot.inherit_from_macrolanguages ()
+ot.names[DEFAULT_LANGUAGE_SYSTEM] = '*/'
+ot.ranks[DEFAULT_LANGUAGE_SYSTEM] = max (ot.ranks.values ()) + 1
+for tricky_ot_tag in filter (lambda tag: re.match ('[A-Z]{3}$', tag), ot.names):
+	possible_bcp_47_tag = tricky_ot_tag.lower ()
+	if possible_bcp_47_tag in bcp_47.names and not ot.from_bcp_47[possible_bcp_47_tag]:
+		ot.add_language (possible_bcp_47_tag, DEFAULT_LANGUAGE_SYSTEM)
+		bcp_47.macrolanguages[possible_bcp_47_tag] = set ()
+ot.sort_languages ()
+
+print ('/* == Start of generated table == */')
+print ('/*')
+print (' * The following table is generated by running:')
+print (' *')
+print (' *   %s languagetags language-subtag-registry' % sys.argv[0])
+print (' *')
+print (' * on files with these headers:')
+print (' *')
+print (' * %s' % ot.header.strip ())
+print (' * %s' % bcp_47.header)
+print (' */')
+print ()
+print ('#ifndef HB_OT_TAG_TABLE_HH')
+print ('#define HB_OT_TAG_TABLE_HH')
+print ()
+
+def hb_tag (tag):
+	"""Convert a tag to ``HB_TAG`` form.
+
+	Args:
+		tag (str): An OpenType tag.
+
+	Returns:
+		A snippet of C++ representing ``tag``.
+	"""
+	if tag == DEFAULT_LANGUAGE_SYSTEM:
+		return 'HB_TAG_NONE\t       '
+	return "HB_TAG('%s','%s','%s','%s')" % tuple (('%-4s' % tag)[:4])
+
+def get_variant_set (name):
+	"""Return a set of variant language names from a name.
+
+	Args:
+		name (str): A list of language names from the BCP 47 registry,
+			joined on ``'\\n'``.
+
+	Returns:
+		A set of normalized language names.
+	"""
+	return set (unicodedata.normalize ('NFD', n.replace ('\u2019', "'"))
+			.encode ('ASCII', 'ignore')
+			.strip ()
+			for n in re.split ('[\n(),]', name) if n)
+
+def language_name_intersection (a, b):
+	"""Return the names in common between two language names.
+
+	Args:
+		a (str): A list of language names from the BCP 47 registry,
+			joined on ``'\\n'``.
+		b (str): A list of language names from the BCP 47 registry,
+			joined on ``'\\n'``.
+
+	Returns:
+		The normalized language names shared by ``a`` and ``b``.
+	"""
+	return get_variant_set (a).intersection (get_variant_set (b))
+
+def get_matching_language_name (intersection, candidates):
+	return next (iter (c for c in candidates if not intersection.isdisjoint (get_variant_set (c))))
+
+def same_tag (bcp_47_tag, ot_tags):
+	return len (bcp_47_tag) == 3 and len (ot_tags) == 1 and bcp_47_tag == ot_tags[0].lower ()
+
+for language_len in (2, 3):
+	if language_len == 3:
+		print ('#ifndef HB_NO_LANGUAGE_LONG')
+	print ('static const LangTag ot_languages%d[] = {' % language_len)
+	for language, tags in sorted (ot.from_bcp_47.items ()):
+		if language == '' or '-' in language:
+			continue
+		if len(language) != language_len: continue
+		commented_out = same_tag (language, tags)
+		for i, tag in enumerate (tags, start=1):
+			print ('%s{%s,\t%s},' % ('/*' if commented_out else '  ', hb_tag (language), hb_tag (tag)), end='')
+			if commented_out:
+				print ('*/', end='')
+			print ('\t/* ', end='')
+			bcp_47_name = bcp_47.names.get (language, '')
+			bcp_47_name_candidates = bcp_47_name.split ('\n')
+			ot_name = ot.names[tag]
+			scope = bcp_47.scopes.get (language, '')
+			if tag == DEFAULT_LANGUAGE_SYSTEM:
+				write (f'{bcp_47_name_candidates[0]}{scope} != {ot.names[language.upper ()]}')
+			else:
+				intersection = language_name_intersection (bcp_47_name, ot_name)
+				if not intersection:
+					write ('%s%s -> %s' % (bcp_47_name_candidates[0], scope, ot_name))
+				else:
+					name = get_matching_language_name (intersection, bcp_47_name_candidates)
+					bcp_47.names[language] = name
+					write ('%s%s' % (name if len (name) > len (ot_name) else ot_name, scope))
+			print (' */')
+	print ('};')
+	if language_len == 3:
+		print ('#endif')
+	print ()
+
+print ('/**')
+print (' * hb_ot_tags_from_complex_language:')
+print (' * @lang_str: a BCP 47 language tag to convert.')
+print (' * @limit: a pointer to the end of the substring of @lang_str to consider for')
+print (' * conversion.')
+print (' * @count: maximum number of language tags to retrieve (IN) and actual number of')
+print (' * language tags retrieved (OUT). If no tags are retrieved, it is not modified.')
+print (' * @tags: array of size at least @language_count to store the language tag')
+print (' * results')
+print (' *')
+print (' * Converts a multi-subtag BCP 47 language tag to language tags.')
+print (' *')
+print (' * Return value: Whether any language systems were retrieved.')
+print (' **/')
+print ('static inline bool')
+print ('hb_ot_tags_from_complex_language (const char   *lang_str,')
+print ('\t\t\t\t  const char   *limit,')
+print ('\t\t\t\t  unsigned int *count /* IN/OUT */,')
+print ('\t\t\t\t  hb_tag_t     *tags /* OUT */)')
+print ('{')
+
+def print_subtag_matches (subtag, string, new_line):
+	if subtag:
+		if new_line:
+			print ()
+			print ('\t&& ', end='')
+		print ('subtag_matches (%s, limit, "-%s", %i)' % (string, subtag, 1 + len (subtag)), end='')
+
+complex_tags = collections.defaultdict (list)
+for initial, group in itertools.groupby ((lt_tags for lt_tags in [
+			(LanguageTag (language), tags)
+			for language, tags in sorted (ot.from_bcp_47.items (),
+				key=lambda i: (-len (i[0]), i[0]))
+		] if lt_tags[0].is_complex ()),
+		key=lambda lt_tags: lt_tags[0].get_group ()):
+	complex_tags[initial] += group
+
+# Calculate the min length of the subtags outside the switch
+min_subtag_len = 100
+for initial, items in sorted (complex_tags.items ()):
+	if initial != 'und':
+		continue
+	for lt, tags in items:
+		if not tags:
+			continue
+		subtag_len = 0
+		subtag_len += 1 + len (lt.script) if lt.script is not None else 0
+		subtag_len += 1 + len (lt.region) if lt.region is not None else 0
+		subtag_len += 1 + len (lt.variant) if lt.variant is not None else 0
+		min_subtag_len = min(subtag_len, min_subtag_len)
+
+print ('  if (limit - lang_str >= %d)' % (min_subtag_len + 2))
+print ('  {')
+print ("    const char *p = strchr (lang_str, '-');")
+print ("    if (!p || p >= limit || limit - p < %i) goto out;" % min_subtag_len)
+for initial, items in sorted (complex_tags.items ()):
+	if initial != 'und':
+		continue
+	for lt, tags in items:
+		if not tags:
+			continue
+		if lt.variant in bcp_47.prefixes:
+			expect (next (iter (bcp_47.prefixes[lt.variant])) == lt.language,
+					'%s is not a valid prefix of %s' % (lt.language, lt.variant))
+		print ('    if (', end='')
+		print_subtag_matches (lt.script, 'p', False)
+		print_subtag_matches (lt.region, 'p', False)
+		print_subtag_matches (lt.variant, 'p', False)
+		print (')')
+		print ('    {')
+		write ('      /* %s */' % bcp_47.get_name (lt))
+		print ()
+		if len (tags) == 1:
+			write ('      tags[0] = %s;  /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
+			print ()
+			print ('      *count = 1;')
+		else:
+			print ('    hb_tag_t possible_tags[] = {')
+			for tag in tags:
+				write ('      %s,  /* %s */' % (hb_tag (tag), ot.names[tag]))
+				print ()
+			print ('      };')
+			print ('      for (i = 0; i < %s && i < *count; i++)' % len (tags))
+			print ('\ttags[i] = possible_tags[i];')
+			print ('      *count = i;')
+		print ('      return true;')
+		print ('    }')
+print ('  }')
+print ('out:')
+
+print ('  switch (lang_str[0])')
+print ('  {')
+for initial, items in sorted (complex_tags.items ()):
+	if initial == 'und':
+		continue
+	print ("  case '%s':" % initial)
+	for lt, tags in items:
+		if not tags:
+			continue
+		print ('    if (', end='')
+		script = lt.script
+		region = lt.region
+		if lt.grandfathered:
+			print ('0 == strcmp (&lang_str[1], "%s")' % lt.language[1:], end='')
+		else:
+			string_literal = lt.language[1:] + '-'
+			if script:
+				string_literal += script
+				script = None
+				if region:
+					string_literal += '-' + region
+					region = None
+			if string_literal[-1] == '-':
+				print ('0 == strncmp (&lang_str[1], "%s", %i)' % (string_literal, len (string_literal)), end='')
+			else:
+				print ('lang_matches (&lang_str[1], limit, "%s", %i)' % (string_literal, len (string_literal)), end='')
+		print_subtag_matches (script, 'lang_str', True)
+		print_subtag_matches (region, 'lang_str', True)
+		print_subtag_matches (lt.variant, 'lang_str', True)
+		print (')')
+		print ('    {')
+		write ('      /* %s */' % bcp_47.get_name (lt))
+		print ()
+		if len (tags) == 1:
+			write ('      tags[0] = %s;  /* %s */' % (hb_tag (tags[0]), ot.names[tags[0]]))
+			print ()
+			print ('      *count = 1;')
+		else:
+			print ('      unsigned int i;')
+			print ('      hb_tag_t possible_tags[] = {')
+			for tag in tags:
+				write ('\t%s,  /* %s */' % (hb_tag (tag), ot.names[tag]))
+				print ()
+			print ('      };')
+			print ('      for (i = 0; i < %s && i < *count; i++)' % len (tags))
+			print ('\ttags[i] = possible_tags[i];')
+			print ('      *count = i;')
+		print ('      return true;')
+		print ('    }')
+	print ('    break;')
+
+print ('  }')
+print ('  return false;')
+print ('}')
+print ()
+print ('/**')
+print (' * hb_ot_ambiguous_tag_to_language')
+print (' * @tag: A language tag.')
+print (' *')
+print (' * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to')
+print (' * many language tags) and the best tag is not the alphabetically first, or if')
+print (' * the best tag consists of multiple subtags, or if the best tag does not appear')
+print (' * in #ot_languages.')
+print (' *')
+print (' * Return value: The #hb_language_t corresponding to the BCP 47 language tag,')
+print (' * or #HB_LANGUAGE_INVALID if @tag is not ambiguous.')
+print (' **/')
+print ('static inline hb_language_t')
+print ('hb_ot_ambiguous_tag_to_language (hb_tag_t tag)')
+print ('{')
+print ('  switch (tag)')
+print ('  {')
+
+def verify_disambiguation_dict ():
+	"""Verify and normalize ``disambiguation``.
+
+	``disambiguation`` is a map of ambiguous OpenType language system
+	tags to the particular BCP 47 tags they correspond to. This function
+	checks that all its keys really are ambiguous and that each key's
+	value is valid for that key. It checks that no ambiguous tag is
+	missing, except when it can figure out which BCP 47 tag is the best
+	by itself.
+
+	It modifies ``disambiguation`` to remove keys whose values are the
+	same as those that the fallback would return anyway, and to add
+	ambiguous keys whose disambiguations it determined automatically.
+
+	Raises:
+		AssertionError: Verification failed.
+	"""
+	global bcp_47
+	global disambiguation
+	global ot
+	for ot_tag, bcp_47_tags in ot.to_bcp_47.items ():
+		if ot_tag == DEFAULT_LANGUAGE_SYSTEM:
+			primary_tags = []
+		else:
+			primary_tags = list (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot.from_bcp_47.get (t)[0] == ot_tag)
+		if len (primary_tags) == 1:
+			expect (ot_tag not in disambiguation, 'unnecessary disambiguation for OT tag: %s' % ot_tag)
+			if '-' in primary_tags[0]:
+				disambiguation[ot_tag] = primary_tags[0]
+			else:
+				first_tag = sorted (t for t in bcp_47_tags if t not in bcp_47.grandfathered and ot_tag in ot.from_bcp_47.get (t))[0]
+				if primary_tags[0] != first_tag:
+					disambiguation[ot_tag] = primary_tags[0]
+		elif len (primary_tags) == 0:
+			expect (ot_tag not in disambiguation, 'There is no possible valid disambiguation for %s' % ot_tag)
+		else:
+			original_languages = [t for t in primary_tags if t in ot.from_bcp_47_uninherited and 'retired code' not in bcp_47.scopes.get (t, '')]
+			if len (original_languages) == 1:
+				macrolanguages = original_languages
+			else:
+				macrolanguages = [t for t in primary_tags if bcp_47.scopes.get (t) == ' [macrolanguage]']
+			if len (macrolanguages) != 1:
+				macrolanguages = list (t for t in primary_tags if bcp_47.scopes.get (t) == ' [collection]')
+			if len (macrolanguages) != 1:
+				macrolanguages = list (t for t in primary_tags if 'retired code' not in bcp_47.scopes.get (t, ''))
+			if len (macrolanguages) != 1:
+				expect (ot_tag in disambiguation, 'ambiguous OT tag: %s %s' % (ot_tag, str (macrolanguages)))
+				expect (disambiguation[ot_tag] in bcp_47_tags,
+						'%s is not a valid disambiguation for %s' % (disambiguation[ot_tag], ot_tag))
+			elif ot_tag not in disambiguation:
+				disambiguation[ot_tag] = macrolanguages[0]
+			different_bcp_47_tags = sorted (t for t in bcp_47_tags if not same_tag (t, ot.from_bcp_47.get (t)))
+			if different_bcp_47_tags and disambiguation[ot_tag] == different_bcp_47_tags[0] and '-' not in disambiguation[ot_tag]:
+				del disambiguation[ot_tag]
+	for ot_tag in disambiguation.keys ():
+		expect (ot_tag in ot.to_bcp_47, 'unknown OT tag: %s' % ot_tag)
+
+verify_disambiguation_dict ()
+for ot_tag, bcp_47_tag in sorted (disambiguation.items ()):
+	write ('  case %s:  /* %s */' % (hb_tag (ot_tag), ot.names[ot_tag]))
+	print ()
+	write ('    return hb_language_from_string (\"%s\", -1);  /* %s */' % (bcp_47_tag, bcp_47.get_name (LanguageTag (bcp_47_tag))))
+	print ()
+
+print ('  default:')
+print ('    return HB_LANGUAGE_INVALID;')
+print ('  }')
+print ('}')
+
+print ()
+print ('#endif /* HB_OT_TAG_TABLE_HH */')
+print ()
+print ('/* == End of generated table == */')
+
diff --git a/gfx/harfbuzz/src/gen-ucd-table.py b/gfx/harfbuzz/src/gen-ucd-table.py
index e5be65a6f1..bb53dcd1dd 100644
--- a/gfx/harfbuzz/src/gen-ucd-table.py
+++ b/gfx/harfbuzz/src/gen-ucd-table.py
@@ -1,202 +1,203 @@
-#!/usr/bin/env python3
-
-"""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]
-
-Input file:
-* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip
-"""
-
-import sys, re
-import logging
-logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
-
-if len (sys.argv) not in (2, 3):
-	sys.exit (__doc__)
-
-# https://github.com/harfbuzz/packtab
-import packTab
-import packTab.ucdxml
-
-logging.info('Loading UCDXML...')
-ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
-ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
-
-hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
-
-logging.info('Preparing data tables...')
-
-
-# This is how the data is encoded:
-#
-# General_Category (gc), Canonical_Combining_Class (ccc),
-# and Script (sc) are encoded as integers.
-#
-# Mirroring character (bmg) is encoded as difference from
-# the original character.
-#
-# Composition & Decomposition (dm) are encoded elaborately,
-# as discussed below.
-
-gc = [u['gc'] for u in ucd]
-ccc = [int(u['ccc']) for u in ucd]
-bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
-sc = [u['sc'] for u in ucd]
-
-
-# Prepare Compose / Decompose data
-#
-# This code is very dense.  See hb_ucd_compose() / hb_ucd_decompose() for the logic.
-
-dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
-      if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
-ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
-
-assert not any(v for v in dm.values() if len(v) not in (1,2))
-dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
-assert all((v[0] >> 16) in (0,2) for v in dm1)
-dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
-dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
-dm1_order = {v:i+1 for i,v in enumerate(dm1)}
-
-dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
-             for i,v in dm.items() if len(v) == 2)
-
-filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
-                  (v[1] & 0xFFFFFF80) == 0x0300 and
-                  (v[2] & 0xFFF0C000) == 0x0000)
-dm2_u32_array = [v for v in dm2 if filt(v[0])]
-dm2_u64_array = [v for v in dm2 if not filt(v[0])]
-assert dm2_u32_array + dm2_u64_array == dm2
-dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
-dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]
-
-l = 1 + len(dm1_p0_array) + len(dm1_p2_array)
-dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
-
-dm_order = {None: 0}
-dm_order.update(dm1_order)
-dm_order.update(dm2_order)
-
-
-# Prepare General_Category / Script mapping arrays
-
-gc_order = dict()
-for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
-                      'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
-                      'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',)):
-    gc_order[i] = v
-    gc_order[v] = i
-
-sc_order = dict()
-sc_array = []
-sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
-for line in open(hb_common_h):
-    m = sc_re.search (line)
-    if not m: continue
-    name = m.group(1)
-    tag = ''.join(m.group(i) for i in range(2, 6))
-    i = len(sc_array)
-    sc_order[tag] = i
-    sc_order[i] = tag
-    sc_array.append(name)
-
-
-# Write out main data
-
-DEFAULT = 'DEFAULT'
-COMPACT = 'COMPACT'
-SLOPPY  = 'SLOPPY'
-
-compression_level = {
-    DEFAULT: 5,
-    COMPACT: 9,
-    SLOPPY:  9,
-}
-
-logging.info('Generating output...')
-print("/* == Start of generated table == */")
-print("/*")
-print(" * The following table is generated by running:")
-print(" *")
-print(" *   ./gen-ucd-table.py ucd.nounihan.grouped.xml")
-print(" *")
-print(" * on file with this description:", ucdxml.description)
-print(" */")
-print()
-print("#ifndef HB_UCD_TABLE_HH")
-print("#define HB_UCD_TABLE_HH")
-print()
-print('#include "hb.hh"')
-print()
-
-
-# Write mapping data
-
-code = packTab.Code('_hb_ucd')
-sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
-dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
-dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
-dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
-dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
-code.print_c(linkage='static inline')
-
-datasets = [
-    ('gc', gc, 'Cn', gc_order),
-    ('ccc', ccc, 0, None),
-    ('bmg', bmg, 0, None),
-    ('sc', sc, 'Zzzz', sc_order),
-    ('dm', dm, None, dm_order),
-]
-
-
-# Write main data
-
-for step in (DEFAULT, COMPACT, SLOPPY):
-    compression = compression_level[step]
-    logging.info('  Compression=%d:' % compression)
-    print()
-    if step == DEFAULT:
-        print('#ifndef HB_OPTIMIZE_SIZE')
-    elif step == COMPACT:
-        print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
-    elif step == SLOPPY:
-        print('#else')
-    else:
-        assert False
-    print()
-
-    if step == SLOPPY:
-        for i in range(len(gc)):
-            if (i % 128) and gc[i] == 'Cn':
-                gc[i] = gc[i - 1]
-        for i in range(len(gc) - 2, -1, -1):
-            if ((i + 1) % 128) and gc[i] == 'Cn':
-                gc[i] = gc[i + 1]
-        for i in range(len(sc)):
-            if (i % 128) and sc[i] == 'Zzzz':
-                sc[i] = sc[i - 1]
-        for i in range(len(sc) - 2, -1, -1):
-            if ((i + 1) % 128) and sc[i] == 'Zzzz':
-                sc[i] = sc[i + 1]
-
-
-    code = packTab.Code('_hb_ucd')
-
-    for name,data,default,mapping in datasets:
-        sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
-        logging.info('      Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
-        sol.genCode(code, name)
-
-    code.print_c(linkage='static inline')
-
-    print()
-
-
-print('#endif')
-print()
-
-print()
-print("#endif /* HB_UCD_TABLE_HH */")
-print()
-print("/* == End of generated table == */")
-logging.info('Done.')
+#!/usr/bin/env python3
+
+"""usage: ./gen-ucd-table ucd.nounihan.grouped.xml [/path/to/hb-common.h]
+
+Input file:
+* https://unicode.org/Public/UCD/latest/ucdxml/ucd.nounihan.grouped.zip
+"""
+
+from __future__ import print_function
+import sys, re
+import logging
+logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
+
+if len (sys.argv) not in (2, 3):
+	sys.exit (__doc__)
+
+# https://github.com/harfbuzz/packtab
+import packTab
+import packTab.ucdxml
+
+logging.info('Loading UCDXML...')
+ucdxml = packTab.ucdxml.load_ucdxml(sys.argv[1])
+ucd = packTab.ucdxml.ucdxml_get_repertoire(ucdxml)
+
+hb_common_h = 'hb-common.h' if len (sys.argv) < 3 else sys.argv[2]
+
+logging.info('Preparing data tables...')
+
+
+# This is how the data is encoded:
+#
+# General_Category (gc), Canonical_Combining_Class (ccc),
+# and Script (sc) are encoded as integers.
+#
+# Mirroring character (bmg) is encoded as difference from
+# the original character.
+#
+# Composition & Decomposition (dm) are encoded elaborately,
+# as discussed below.
+
+gc = [u['gc'] for u in ucd]
+ccc = [int(u['ccc']) for u in ucd]
+bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)]
+sc = [u['sc'] for u in ucd]
+
+
+# Prepare Compose / Decompose data
+#
+# This code is very dense.  See hb_ucd_compose() / hb_ucd_decompose() for the logic.
+
+dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd)
+      if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)}
+ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'}
+
+assert not any(v for v in dm.values() if len(v) not in (1,2))
+dm1 = sorted(set(v for v in dm.values() if len(v) == 1))
+assert all((v[0] >> 16) in (0,2) for v in dm1)
+dm1_p0_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 0]
+dm1_p2_array = ['0x%04Xu' % (v[0] & 0xFFFF) for v in dm1 if (v[0] >> 16) == 2]
+dm1_order = {v:i+1 for i,v in enumerate(dm1)}
+
+dm2 = sorted((v+(i if i not in ce and not ccc[i] else 0,), v)
+             for i,v in dm.items() if len(v) == 2)
+
+filt = lambda v: ((v[0] & 0xFFFFF800) == 0x0000 and
+                  (v[1] & 0xFFFFFF80) == 0x0300 and
+                  (v[2] & 0xFFF0C000) == 0x0000)
+dm2_u32_array = [v for v in dm2 if filt(v[0])]
+dm2_u64_array = [v for v in dm2 if not filt(v[0])]
+assert dm2_u32_array + dm2_u64_array == dm2
+dm2_u32_array = ["HB_CODEPOINT_ENCODE3_11_7_14 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u32_array]
+dm2_u64_array = ["HB_CODEPOINT_ENCODE3 (0x%04Xu, 0x%04Xu, 0x%04Xu)" % v[0] for v in dm2_u64_array]
+
+l = 1 + len(dm1_p0_array) + len(dm1_p2_array)
+dm2_order = {v[1]:i+l for i,v in enumerate(dm2)}
+
+dm_order = {None: 0}
+dm_order.update(dm1_order)
+dm_order.update(dm2_order)
+
+
+# Prepare General_Category / Script mapping arrays
+
+gc_order = dict()
+for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu',
+                      'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf',
+                      'Pi', 'Po', 'Ps', 'Sc', 'Sk', 'Sm', 'So', 'Zl', 'Zp', 'Zs',)):
+    gc_order[i] = v
+    gc_order[v] = i
+
+sc_order = dict()
+sc_array = []
+sc_re = re.compile(r"\b(HB_SCRIPT_[_A-Z]*).*HB_TAG [(]'(.)','(.)','(.)','(.)'[)]")
+for line in open(hb_common_h):
+    m = sc_re.search (line)
+    if not m: continue
+    name = m.group(1)
+    tag = ''.join(m.group(i) for i in range(2, 6))
+    i = len(sc_array)
+    sc_order[tag] = i
+    sc_order[i] = tag
+    sc_array.append(name)
+
+
+# Write out main data
+
+DEFAULT = 'DEFAULT'
+COMPACT = 'COMPACT'
+SLOPPY  = 'SLOPPY'
+
+compression_level = {
+    DEFAULT: 5,
+    COMPACT: 9,
+    SLOPPY:  9,
+}
+
+logging.info('Generating output...')
+print("/* == Start of generated table == */")
+print("/*")
+print(" * The following table is generated by running:")
+print(" *")
+print(" *   ./gen-ucd-table.py ucd.nounihan.grouped.xml")
+print(" *")
+print((" * on file with this description:", ucdxml.description))
+print(" */")
+print()
+print("#ifndef HB_UCD_TABLE_HH")
+print("#define HB_UCD_TABLE_HH")
+print()
+print('#include "hb.hh"')
+print()
+
+
+# Write mapping data
+
+code = packTab.Code('_hb_ucd')
+sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array)
+dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array)
+dm1_p2_array, _ = code.addArray('uint16_t', 'dm1_p2_map', dm1_p2_array)
+dm2_u32_array, _ = code.addArray('uint32_t', 'dm2_u32_map', dm2_u32_array)
+dm2_u64_array, _ = code.addArray('uint64_t', 'dm2_u64_map', dm2_u64_array)
+code.print_c(linkage='static inline')
+
+datasets = [
+    ('gc', gc, 'Cn', gc_order),
+    ('ccc', ccc, 0, None),
+    ('bmg', bmg, 0, None),
+    ('sc', sc, 'Zzzz', sc_order),
+    ('dm', dm, None, dm_order),
+]
+
+
+# Write main data
+
+for step in (DEFAULT, COMPACT, SLOPPY):
+    compression = compression_level[step]
+    logging.info('  Compression=%d:' % compression)
+    print()
+    if step == DEFAULT:
+        print('#ifndef HB_OPTIMIZE_SIZE')
+    elif step == COMPACT:
+        print('#elif !defined(HB_NO_UCD_UNASSIGNED)')
+    elif step == SLOPPY:
+        print('#else')
+    else:
+        assert False
+    print()
+
+    if step == SLOPPY:
+        for i in range(len(gc)):
+            if (i % 128) and gc[i] == 'Cn':
+                gc[i] = gc[i - 1]
+        for i in range(len(gc) - 2, -1, -1):
+            if ((i + 1) % 128) and gc[i] == 'Cn':
+                gc[i] = gc[i + 1]
+        for i in range(len(sc)):
+            if (i % 128) and sc[i] == 'Zzzz':
+                sc[i] = sc[i - 1]
+        for i in range(len(sc) - 2, -1, -1):
+            if ((i + 1) % 128) and sc[i] == 'Zzzz':
+                sc[i] = sc[i + 1]
+
+
+    code = packTab.Code('_hb_ucd')
+
+    for name,data,default,mapping in datasets:
+        sol = packTab.pack_table(data, default, mapping=mapping, compression=compression)
+        logging.info('      Dataset=%-8s FullCost=%d' % (name, sol.fullCost))
+        sol.genCode(code, name)
+
+    code.print_c(linkage='static inline')
+
+    print()
+
+
+print('#endif')
+print()
+
+print()
+print("#endif /* HB_UCD_TABLE_HH */")
+print()
+print("/* == End of generated table == */")
+logging.info('Done.')
diff --git a/gfx/harfbuzz/src/gen-vowel-constraints.py b/gfx/harfbuzz/src/gen-vowel-constraints.py
index 5bb5e9e8e8..299e612fd0 100644
--- a/gfx/harfbuzz/src/gen-vowel-constraints.py
+++ b/gfx/harfbuzz/src/gen-vowel-constraints.py
@@ -1,229 +1,230 @@
-#!/usr/bin/env python3
-
-"""Generator of the function to prohibit certain vowel sequences.
-
-It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted
-circles into sequences prohibited by the USE script development spec.
-This function should be used as the ``preprocess_text`` of an
-``hb_ot_shaper_t``.
-
-usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
-
-Input file:
-* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
-"""
-
-import collections
-def write (s):
-	sys.stdout.flush ()
-	sys.stdout.buffer.write (s.encode ('utf-8'))
-import sys
-
-if len (sys.argv) != 3:
-	sys.exit (__doc__)
-
-with open (sys.argv[2], encoding='utf-8') as f:
-	scripts_header = [f.readline () for i in range (2)]
-	scripts = {}
-	script_order = {}
-	for line in f:
-		j = line.find ('#')
-		if j >= 0:
-			line = line[:j]
-		fields = [x.strip () for x in line.split (';')]
-		if len (fields) == 1:
-			continue
-		uu = fields[0].split ('..')
-		start = int (uu[0], 16)
-		if len (uu) == 1:
-			end = start
-		else:
-			end = int (uu[1], 16)
-		script = fields[1]
-		for u in range (start, end + 1):
-			scripts[u] = script
-		if script not in script_order:
-			script_order[script] = start
-
-class ConstraintSet (object):
-	"""A set of prohibited code point sequences.
-
-	Args:
-		constraint (List[int]): A prohibited code point sequence.
-
-	"""
-	def __init__ (self, constraint):
-		# Either a list or a dictionary. As a list of code points, it
-		# represents a prohibited code point sequence. As a dictionary,
-		# it represents a set of prohibited sequences, where each item
-		# represents the set of prohibited sequences starting with the
-		# key (a code point) concatenated with any of the values
-		# (ConstraintSets).
-		self._c = constraint
-
-	def add (self, constraint):
-		"""Add a constraint to this set."""
-		if not constraint:
-			return
-		first = constraint[0]
-		rest = constraint[1:]
-		if isinstance (self._c, list):
-			if constraint == self._c[:len (constraint)]:
-				self._c = constraint
-			elif self._c != constraint[:len (self._c)]:
-				self._c = {self._c[0]: ConstraintSet (self._c[1:])}
-		if isinstance (self._c, dict):
-			if first in self._c:
-				self._c[first].add (rest)
-			else:
-				self._c[first] = ConstraintSet (rest)
-
-	@staticmethod
-	def _indent (depth):
-		return ('  ' * depth).replace ('        ', '\t')
-
-	def __str__ (self, index=0, depth=4):
-		s = []
-		indent = self._indent (depth)
-		if isinstance (self._c, list):
-			if len (self._c) == 0:
-				assert index == 2, 'Cannot use `matched` for this constraint; the general case has not been implemented'
-				s.append ('{}matched = true;\n'.format (indent))
-			elif len (self._c) == 1:
-				assert index == 1, 'Cannot use `matched` for this constraint; the general case has not been implemented'
-				s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
-			else:
-				s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index or ''))
-				if index:
-					s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), index + 1))
-				for i, cp in enumerate (self._c[1:], start=1):
-					s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
-						self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
-				s.append ('{}{{\n'.format (indent))
-				for i in range (index):
-					s.append ('{}(void) buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
-				s.append ('{}matched = true;\n'.format (self._indent (depth + 1)))
-				s.append ('{}}}\n'.format (indent))
-		else:
-			s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or ''))
-			s.append ('{}{{\n'.format (indent))
-			cases = collections.defaultdict (set)
-			for first, rest in sorted (self._c.items ()):
-				cases[rest.__str__ (index + 1, depth + 2)].add (first)
-			for body, labels in sorted (cases.items (), key=lambda b_ls: sorted (b_ls[1])[0]):
-				for i, cp in enumerate (sorted (labels)):
-					if i % 4 == 0:
-						s.append (self._indent (depth + 1))
-					else:
-						s.append (' ')
-					s.append ('case 0x{:04X}u:{}'.format (cp, '\n' if i % 4 == 3 else ''))
-				if len (labels) % 4 != 0:
-					s.append ('\n')
-				s.append (body)
-				s.append ('{}break;\n'.format (self._indent (depth + 2)))
-			s.append ('{}}}\n'.format (indent))
-		return ''.join (s)
-
-constraints = {}
-with open (sys.argv[1], encoding='utf-8') as f:
-	constraints_header = []
-	while True:
-		line = f.readline ().strip ()
-		if line == '#':
-			break
-		constraints_header.append(line)
-	for line in f:
-		j = line.find ('#')
-		if j >= 0:
-			line = line[:j]
-		constraint = [int (cp, 16) for cp in line.split (';')[0].split ()]
-		if not constraint: continue
-		assert 2 <= len (constraint), 'Prohibited sequence is too short: {}'.format (constraint)
-		script = scripts[constraint[0]]
-		if script in constraints:
-			constraints[script].add (constraint)
-		else:
-			constraints[script] = ConstraintSet (constraint)
-		assert constraints, 'No constraints found'
-
-print ('/* == Start of generated functions == */')
-print ('/*')
-print (' * The following functions are generated by running:')
-print (' *')
-print (' *   %s ms-use/IndicShapingInvalidCluster.txt Scripts.txt' % sys.argv[0])
-print (' *')
-print (' * on files with these headers:')
-print (' *')
-for line in constraints_header:
-	print (' * %s' % line.strip ())
-print (' *')
-for line in scripts_header:
-	print (' * %s' % line.strip ())
-print (' */')
-
-print ()
-print ('#include "hb.hh"')
-print ()
-print ('#ifndef HB_NO_OT_SHAPE')
-print ()
-print ('#include "hb-ot-shaper-vowel-constraints.hh"')
-print ()
-print ('static void')
-print ('_output_dotted_circle (hb_buffer_t *buffer)')
-print ('{')
-print ('  (void) buffer->output_glyph (0x25CCu);')
-print ('  _hb_glyph_info_reset_continuation (&buffer->prev());')
-print ('}')
-print ()
-print ('static void')
-print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
-print ('{')
-print ('  _output_dotted_circle (buffer);')
-print ('  (void) buffer->next_glyph ();')
-print ('}')
-print ()
-
-print ('void')
-print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,')
-print ('\t\t\t\t       hb_buffer_t              *buffer,')
-print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
-print ('{')
-print ('#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS')
-print ('  return;')
-print ('#endif')
-print ('  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
-print ('    return;')
-print ()
-print ('  /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
-print ('   * vowel-sequences that look like another vowel.  Data for each script')
-print ('   * collected from the USE script development spec.')
-print ('   *')
-print ('   * https://github.com/harfbuzz/harfbuzz/issues/1019')
-print ('   */')
-print ('  buffer->clear_output ();')
-print ('  unsigned int count = buffer->len;')
-print ('  switch ((unsigned) buffer->props.script)')
-print ('  {')
-
-for script, constraints in sorted (constraints.items (), key=lambda s_c: script_order[s_c[0]]):
-	print ('    case HB_SCRIPT_{}:'.format (script.upper ()))
-	print ('      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)')
-	print ('      {')
-	print ('\tbool matched = false;')
-	write (str (constraints))
-	print ('\t(void) buffer->next_glyph ();')
-	print ('\tif (matched) _output_with_dotted_circle (buffer);')
-	print ('      }')
-	print ('      break;')
-	print ()
-
-print ('    default:')
-print ('      break;')
-print ('  }')
-print ('  buffer->sync ();')
-print ('}')
-
-print ()
-print ()
-print ('#endif')
-print ('/* == End of generated functions == */')
+#!/usr/bin/env python3
+
+"""Generator of the function to prohibit certain vowel sequences.
+
+It creates ``_hb_preprocess_text_vowel_constraints``, which inserts dotted
+circles into sequences prohibited by the USE script development spec.
+This function should be used as the ``preprocess_text`` of an
+``hb_ot_shaper_t``.
+
+usage: ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt
+
+Input file:
+* https://unicode.org/Public/UCD/latest/ucd/Scripts.txt
+"""
+
+from __future__ import print_function
+import collections
+def write (s):
+	sys.stdout.flush ()
+	sys.stdout.buffer.write (s.encode ('utf-8'))
+import sys
+
+if len (sys.argv) != 3:
+	sys.exit (__doc__)
+
+with open (sys.argv[2], encoding='utf-8') as f:
+	scripts_header = [f.readline () for i in range (2)]
+	scripts = {}
+	script_order = {}
+	for line in f:
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+		fields = [x.strip () for x in line.split (';')]
+		if len (fields) == 1:
+			continue
+		uu = fields[0].split ('..')
+		start = int (uu[0], 16)
+		if len (uu) == 1:
+			end = start
+		else:
+			end = int (uu[1], 16)
+		script = fields[1]
+		for u in range (start, end + 1):
+			scripts[u] = script
+		if script not in script_order:
+			script_order[script] = start
+
+class ConstraintSet (object):
+	"""A set of prohibited code point sequences.
+
+	Args:
+		constraint (List[int]): A prohibited code point sequence.
+
+	"""
+	def __init__ (self, constraint):
+		# Either a list or a dictionary. As a list of code points, it
+		# represents a prohibited code point sequence. As a dictionary,
+		# it represents a set of prohibited sequences, where each item
+		# represents the set of prohibited sequences starting with the
+		# key (a code point) concatenated with any of the values
+		# (ConstraintSets).
+		self._c = constraint
+
+	def add (self, constraint):
+		"""Add a constraint to this set."""
+		if not constraint:
+			return
+		first = constraint[0]
+		rest = constraint[1:]
+		if isinstance (self._c, list):
+			if constraint == self._c[:len (constraint)]:
+				self._c = constraint
+			elif self._c != constraint[:len (self._c)]:
+				self._c = {self._c[0]: ConstraintSet (self._c[1:])}
+		if isinstance (self._c, dict):
+			if first in self._c:
+				self._c[first].add (rest)
+			else:
+				self._c[first] = ConstraintSet (rest)
+
+	@staticmethod
+	def _indent (depth):
+		return ('  ' * depth).replace ('        ', '\t')
+
+	def __str__ (self, index=0, depth=4):
+		s = []
+		indent = self._indent (depth)
+		if isinstance (self._c, list):
+			if len (self._c) == 0:
+				assert index == 2, 'Cannot use `matched` for this constraint; the general case has not been implemented'
+				s.append ('{}matched = true;\n'.format (indent))
+			elif len (self._c) == 1:
+				assert index == 1, 'Cannot use `matched` for this constraint; the general case has not been implemented'
+				s.append ('{}matched = 0x{:04X}u == buffer->cur ({}).codepoint;\n'.format (indent, next (iter (self._c)), index or ''))
+			else:
+				s.append ('{}if (0x{:04X}u == buffer->cur ({}).codepoint &&\n'.format (indent, self._c[0], index or ''))
+				if index:
+					s.append ('{}buffer->idx + {} < count &&\n'.format (self._indent (depth + 2), index + 1))
+				for i, cp in enumerate (self._c[1:], start=1):
+					s.append ('{}0x{:04X}u == buffer->cur ({}).codepoint{}\n'.format (
+						self._indent (depth + 2), cp, index + i, ')' if i == len (self._c) - 1 else ' &&'))
+				s.append ('{}{{\n'.format (indent))
+				for i in range (index):
+					s.append ('{}(void) buffer->next_glyph ();\n'.format (self._indent (depth + 1)))
+				s.append ('{}matched = true;\n'.format (self._indent (depth + 1)))
+				s.append ('{}}}\n'.format (indent))
+		else:
+			s.append ('{}switch (buffer->cur ({}).codepoint)\n'.format(indent, index or ''))
+			s.append ('{}{{\n'.format (indent))
+			cases = collections.defaultdict (set)
+			for first, rest in sorted (self._c.items ()):
+				cases[rest.__str__ (index + 1, depth + 2)].add (first)
+			for body, labels in sorted (list(cases.items ()), key=lambda b_ls: sorted (b_ls[1])[0]):
+				for i, cp in enumerate (sorted (labels)):
+					if i % 4 == 0:
+						s.append (self._indent (depth + 1))
+					else:
+						s.append (' ')
+					s.append ('case 0x{:04X}u:{}'.format (cp, '\n' if i % 4 == 3 else ''))
+				if len (labels) % 4 != 0:
+					s.append ('\n')
+				s.append (body)
+				s.append ('{}break;\n'.format (self._indent (depth + 2)))
+			s.append ('{}}}\n'.format (indent))
+		return ''.join (s)
+
+constraints = {}
+with open (sys.argv[1], encoding='utf-8') as f:
+	constraints_header = []
+	while True:
+		line = f.readline ().strip ()
+		if line == '#':
+			break
+		constraints_header.append(line)
+	for line in f:
+		j = line.find ('#')
+		if j >= 0:
+			line = line[:j]
+		constraint = [int (cp, 16) for cp in line.split (';')[0].split ()]
+		if not constraint: continue
+		assert 2 <= len (constraint), 'Prohibited sequence is too short: {}'.format (constraint)
+		script = scripts[constraint[0]]
+		if script in constraints:
+			constraints[script].add (constraint)
+		else:
+			constraints[script] = ConstraintSet (constraint)
+		assert constraints, 'No constraints found'
+
+print ('/* == Start of generated functions == */')
+print ('/*')
+print (' * The following functions are generated by running:')
+print (' *')
+print((' *   %s ms-use/IndicShapingInvalidCluster.txt Scripts.txt' % sys.argv[0]))
+print (' *')
+print (' * on files with these headers:')
+print (' *')
+for line in constraints_header:
+	print((' * %s' % line.strip ()))
+print (' *')
+for line in scripts_header:
+	print((' * %s' % line.strip ()))
+print (' */')
+
+print ()
+print ('#include "hb.hh"')
+print ()
+print ('#ifndef HB_NO_OT_SHAPE')
+print ()
+print ('#include "hb-ot-shaper-vowel-constraints.hh"')
+print ()
+print ('static void')
+print ('_output_dotted_circle (hb_buffer_t *buffer)')
+print ('{')
+print ('  (void) buffer->output_glyph (0x25CCu);')
+print ('  _hb_glyph_info_reset_continuation (&buffer->prev());')
+print ('}')
+print ()
+print ('static void')
+print ('_output_with_dotted_circle (hb_buffer_t *buffer)')
+print ('{')
+print ('  _output_dotted_circle (buffer);')
+print ('  (void) buffer->next_glyph ();')
+print ('}')
+print ()
+
+print ('void')
+print ('_hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,')
+print ('\t\t\t\t       hb_buffer_t              *buffer,')
+print ('\t\t\t\t       hb_font_t                *font HB_UNUSED)')
+print ('{')
+print ('#ifdef HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS')
+print ('  return;')
+print ('#endif')
+print ('  if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)')
+print ('    return;')
+print ()
+print ('  /* UGLY UGLY UGLY business of adding dotted-circle in the middle of')
+print ('   * vowel-sequences that look like another vowel.  Data for each script')
+print ('   * collected from the USE script development spec.')
+print ('   *')
+print ('   * https://github.com/harfbuzz/harfbuzz/issues/1019')
+print ('   */')
+print ('  buffer->clear_output ();')
+print ('  unsigned int count = buffer->len;')
+print ('  switch ((unsigned) buffer->props.script)')
+print ('  {')
+
+for script, constraints in sorted (list(constraints.items ()), key=lambda s_c: script_order[s_c[0]]):
+	print(('    case HB_SCRIPT_{}:'.format (script.upper ())))
+	print ('      for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)')
+	print ('      {')
+	print ('\tbool matched = false;')
+	write (str (constraints))
+	print ('\t(void) buffer->next_glyph ();')
+	print ('\tif (matched) _output_with_dotted_circle (buffer);')
+	print ('      }')
+	print ('      break;')
+	print ()
+
+print ('    default:')
+print ('      break;')
+print ('  }')
+print ('  buffer->sync ();')
+print ('}')
+
+print ()
+print ()
+print ('#endif')
+print ('/* == End of generated functions == */')
diff --git a/gfx/harfbuzz/src/sample.py b/gfx/harfbuzz/src/sample.py
index 654c8e8d5c..eef72de5d1 100755
--- a/gfx/harfbuzz/src/sample.py
+++ b/gfx/harfbuzz/src/sample.py
@@ -1,65 +1,66 @@
-#!/usr/bin/env python3
-
-import sys
-import array
-import gi
-gi.require_version('HarfBuzz', '0.0')
-from gi.repository import HarfBuzz as hb
-from gi.repository import GLib
-
-fontdata = open (sys.argv[1], 'rb').read ()
-text = sys.argv[2]
-# Need to create GLib.Bytes explicitly until this bug is fixed:
-# https://bugzilla.gnome.org/show_bug.cgi?id=729541
-blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
-face = hb.face_create (blob, 0)
-del blob
-font = hb.font_create (face)
-upem = hb.face_get_upem (face)
-del face
-hb.font_set_scale (font, upem, upem)
-#hb.ft_font_set_funcs (font)
-hb.ot_font_set_funcs (font)
-
-buf = hb.buffer_create ()
-class Debugger (object):
-	def message (self, buf, font, msg, data, _x_what_is_this):
-		print (msg)
-		return True
-debugger = Debugger ()
-hb.buffer_set_message_func (buf, debugger.message, 1, 0)
-
-##
-## Add text to buffer
-##
-#
-# See https://github.com/harfbuzz/harfbuzz/pull/271
-#
-# If you do not care about cluster values reflecting Python
-# string indices, then this is quickest way to add text to
-# buffer:
-# hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
-# Otherwise, then following handles both narrow and wide
-# Python builds (the first item in the array is BOM, so we skip it):
-if sys.maxunicode == 0x10FFFF:
-	hb.buffer_add_utf32 (buf, array.array ('I', text.encode ('utf-32'))[1:], 0, -1)
-else:
-	hb.buffer_add_utf16 (buf, array.array ('H', text.encode ('utf-16'))[1:], 0, -1)
-
-
-hb.buffer_guess_segment_properties (buf)
-
-hb.shape (font, buf, [])
-del font
-
-infos = hb.buffer_get_glyph_infos (buf)
-positions = hb.buffer_get_glyph_positions (buf)
-
-for info, pos in zip (infos, positions):
-	gid = info.codepoint
-	cluster = info.cluster
-	x_advance = pos.x_advance
-	x_offset = pos.x_offset
-	y_offset = pos.y_offset
-
-	print ("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset))
+#!/usr/bin/env python3
+
+from __future__ import print_function
+import sys
+import array
+import gi
+gi.require_version('HarfBuzz', '0.0')
+from gi.repository import HarfBuzz as hb
+from gi.repository import GLib
+
+fontdata = open (sys.argv[1], 'rb').read ()
+text = sys.argv[2]
+# Need to create GLib.Bytes explicitly until this bug is fixed:
+# https://bugzilla.gnome.org/show_bug.cgi?id=729541
+blob = hb.glib_blob_create (GLib.Bytes.new (fontdata))
+face = hb.face_create (blob, 0)
+del blob
+font = hb.font_create (face)
+upem = hb.face_get_upem (face)
+del face
+hb.font_set_scale (font, upem, upem)
+#hb.ft_font_set_funcs (font)
+hb.ot_font_set_funcs (font)
+
+buf = hb.buffer_create ()
+class Debugger (object):
+	def message (self, buf, font, msg, data, _x_what_is_this):
+		print (msg)
+		return True
+debugger = Debugger ()
+hb.buffer_set_message_func (buf, debugger.message, 1, 0)
+
+##
+## Add text to buffer
+##
+#
+# See https://github.com/harfbuzz/harfbuzz/pull/271
+#
+# If you do not care about cluster values reflecting Python
+# string indices, then this is quickest way to add text to
+# buffer:
+# hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1)
+# Otherwise, then following handles both narrow and wide
+# Python builds (the first item in the array is BOM, so we skip it):
+if sys.maxunicode == 0x10FFFF:
+	hb.buffer_add_utf32 (buf, array.array ('I', text.encode ('utf-32'))[1:], 0, -1)
+else:
+	hb.buffer_add_utf16 (buf, array.array ('H', text.encode ('utf-16'))[1:], 0, -1)
+
+
+hb.buffer_guess_segment_properties (buf)
+
+hb.shape (font, buf, [])
+del font
+
+infos = hb.buffer_get_glyph_infos (buf)
+positions = hb.buffer_get_glyph_positions (buf)
+
+for info, pos in zip (infos, positions):
+	gid = info.codepoint
+	cluster = info.cluster
+	x_advance = pos.x_advance
+	x_offset = pos.x_offset
+	y_offset = pos.y_offset
+
+	print(("gid%d=%d@%d,%d+%d" % (gid, cluster, x_advance, x_offset, y_offset)))
diff --git a/gfx/skia/generate_mozbuild.py b/gfx/skia/generate_mozbuild.py
index 33594bd32c..ed770d733d 100755
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os
 
 import locale
@@ -166,7 +167,7 @@ def generate_platform_sources():
 
   for plat in platforms:
     if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=%s -D host_os=linux gyp/skia_lib.gyp" % plat) != 0:
-      print 'Failed to generate sources for ' + plat
+      print('Failed to generate sources for ' + plat)
       continue
 
 
@@ -174,7 +175,7 @@ def generate_platform_sources():
     sources[plat] = set(v.replace('../', 'skia/') for v in json.load(f));
     f.close()
 
-  return dict(sources.items() + generate_opt_sources().items())
+  return dict(list(sources.items()) + list(generate_opt_sources().items()))
 
 
 def generate_separated_sources(platform_sources):
@@ -308,11 +309,11 @@ def generate_separated_sources(platform_sources):
       separated[key].add(value)
 
   if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=linux -D host_os=linux -R pdf gyp/pdf.gyp") != 0:
-    print 'Failed to generate sources for Skia PDF'
+    print('Failed to generate sources for Skia PDF')
   else:
     f = open('skia/sources.json');
     separated['pdf'].add('skia/src/core/SkMD5.cpp');
-    separated['pdf'].update(filter(lambda x: 'pdf' in x, set(v.replace('../', 'skia/') for v in json.load(f))));
+    separated['pdf'].update([x for x in set(v.replace('../', 'skia/') for v in json.load(f)) if 'pdf' in x]);
     f.close()
 
   return separated
@@ -479,7 +480,7 @@ def write_mozbuild(sources):
 
   f.close()
 
-  print 'Wrote ' + filename
+  print('Wrote ' + filename)
 
 def main():
   platform_sources = generate_platform_sources()
diff --git a/gfx/thebes/genTables.py b/gfx/thebes/genTables.py
index 0e902c52aa..28374bd200 100644
--- a/gfx/thebes/genTables.py
+++ b/gfx/thebes/genTables.py
@@ -8,10 +8,10 @@ def table_generator(f):
 
 def generate(output):
     output.write("const uint8_t gfxUtils::sPremultiplyTable[256*256] = {\n");
-    output.write(table_generator(lambda i: ((i / 256) * (i % 256) + 254) / 255) + "\n")
+    output.write(table_generator(lambda i: int((i // 256 * (i % 256) + 254) / 255)) + "\n")
     output.write("};\n");
     output.write("const uint8_t gfxUtils::sUnpremultiplyTable[256*256] = {\n");
-    output.write(table_generator(lambda i: (i % 256) * 255 / ((i / 256) if (i / 256) > 0 else 255) % 256) + "\n")
+    output.write(table_generator(lambda i: int((i % 256) * 255 / (i // 256 if i // 256 > 0 else 255) % 256)) + "\n")
     output.write("};\n");
 
 if __name__ == '__main__':
diff --git a/intl/icu/source/python/icutools/databuilder/utils.py b/intl/icu/source/python/icutools/databuilder/utils.py
index 3d53d18fae..5bd16393d0 100644
--- a/intl/icu/source/python/icutools/databuilder/utils.py
+++ b/intl/icu/source/python/icutools/databuilder/utils.py
@@ -77,12 +77,12 @@ def repeated_execution_request_looper(request):
     # dictionary of lists to list of dictionaries:
     ld = [
         dict(zip(request.repeat_with, t))
-        for t in zip(*request.repeat_with.values())
+        for t in zip(*list(request.repeat_with.values()))
     ]
     if not ld:
         # No special options given in repeat_with
         ld = [{} for _ in range(len(request.input_files))]
-    return zip(ld, request.specific_dep_files, request.input_files, request.output_files)
+    return list(zip(ld, request.specific_dep_files, request.input_files, request.output_files))
 
 
 def format_single_request_command(request, cmd_template, common_vars):
diff --git a/intl/locale/props2arrays.py b/intl/locale/props2arrays.py
index 510e0d51a0..3b3e564362 100644
--- a/intl/locale/props2arrays.py
+++ b/intl/locale/props2arrays.py
@@ -15,7 +15,7 @@ def main(header, propFile):
         if len(parts) == 2 and len(parts[0]) > 0:
           mappings[parts[0].strip()] = parts[1].strip()
  
-  keys = mappings.keys()
+  keys = list(mappings.keys())
   keys.sort()
 
   header.write("// This is a generated file. Please do not edit.\n")
diff --git a/intl/uconv/tools/gen-big5-data.py b/intl/uconv/tools/gen-big5-data.py
index 1d0f59bb43..4bce14a368 100644
--- a/intl/uconv/tools/gen-big5-data.py
+++ b/intl/uconv/tools/gen-big5-data.py
@@ -91,7 +91,7 @@ static const char16_t kBig5LowBitsTable[] = {
 ''')
 
 for (low, high) in ranges:
-  for i in xrange(low, high):
+  for i in range(low, high):
     classFile.write('  0x%04X,\n' % (index[i] & 0xFFFF))
 
 classFile.write('''};
@@ -104,15 +104,15 @@ static const uint32_t kBig5AstralnessTable[] = {
 
 bits = []
 for (low, high) in astralRanges:
-  for i in xrange(low, high):
+  for i in range(low, high):
     bits.append(1 if index[i] > 0xFFFF else 0)
 # pad length to multiple of 32
-for i in xrange(32 - (len(bits) % 32)):
+for i in range(32 - (len(bits) % 32)):
   bits.append(0)
 i = 0
 while i < len(bits):
   accu = 0
-  for j in xrange(32):
+  for j in range(32):
     accu |= bits[i + j] << j
   classFile.write('  0x%08X,\n' % accu)
   i += 32
@@ -190,7 +190,7 @@ preferLast = [
 
 for codePoint in preferLast:
   # Python lists don't have .rindex() :-(
-  for i in xrange(len(index) - 1, -1, -1):
+  for i in range(len(index) - 1, -1, -1):
     candidate = index[i]
     if candidate == codePoint:
        classFile.write('''      case 0x%04X:
diff --git a/ipc/chromium/src/third_party/libevent/event_rpcgen.py b/ipc/chromium/src/third_party/libevent/event_rpcgen.py
index dead34c21c..06ef1d8f3f 100755
--- a/ipc/chromium/src/third_party/libevent/event_rpcgen.py
+++ b/ipc/chromium/src/third_party/libevent/event_rpcgen.py
@@ -14,6 +14,7 @@
 #    progress outputs that space stderr at the moment)
 # 3) emit other languages
 
+from __future__ import print_function
 import sys
 import re
 
@@ -33,7 +34,7 @@ headerdirect = []
 cppdirect = []
 
 def TranslateList(mylist, mydict):
-    return map(lambda x: x % mydict, mylist)
+    return [x % mydict for x in mylist]
 
 # Exception class for parse errors
 class RpcGenError(Exception):
@@ -48,17 +49,17 @@ class Struct:
         self._name = name
         self._entries = []
         self._tags = {}
-        print >>sys.stderr, '  Created struct: %s' % name
+        print('  Created struct: %s' % name, file=sys.stderr)
 
     def AddEntry(self, entry):
-        if self._tags.has_key(entry.Tag()):
+        if entry.Tag() in self._tags:
             raise RpcGenError(
                 'Entry "%s" duplicates tag number %d from "%s" '
                 'around line %d' % (entry.Name(), entry.Tag(),
                                     self._tags[entry.Tag()], line_count))
         self._entries.append(entry)
         self._tags[entry.Tag()] = entry.Name()
-        print >>sys.stderr, '    Added entry: %s' % entry.Name()
+        print('    Added entry: %s' % entry.Name(), file=sys.stderr)
 
     def Name(self):
         return self._name
@@ -72,7 +73,7 @@ class Struct:
     def PrintIndented(self, file, ident, code):
         """Takes an array, add indentation to each entry and prints it."""
         for entry in code:
-            print >>file, '%s%s' % (ident, entry)
+            print('%s%s' % (ident, entry), file=file)
 
 class StructCCode(Struct):
     """ Knows how to generate C code for a struct """
@@ -82,20 +83,20 @@ class StructCCode(Struct):
 
     def PrintTags(self, file):
         """Prints the tag definitions for a structure."""
-        print >>file, '/* Tag definition for %s */' % self._name
-        print >>file, 'enum %s_ {' % self._name.lower()
+        print('/* Tag definition for %s */' % self._name, file=file)
+        print('enum %s_ {' % self._name.lower(), file=file)
         for entry in self._entries:
-            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
-                                        entry.Tag())
-        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
-        print >>file, '};\n'
+            print('  %s=%d,' % (self.EntryTagName(entry),
+                                        entry.Tag()), file=file)
+        print('  %s_MAX_TAGS' % (self._name.upper()), file=file)
+        print('};\n', file=file)
 
     def PrintForwardDeclaration(self, file):
-        print >>file, 'struct %s;' % self._name
+        print('struct %s;' % self._name, file=file)
 
     def PrintDeclaration(self, file):
-        print >>file, '/* Structure declaration for %s */' % self._name
-        print >>file, 'struct %s_access_ {' % self._name
+        print('/* Structure declaration for %s */' % self._name, file=file)
+        print('struct %s_access_ {' % self._name, file=file)
         for entry in self._entries:
             dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
             dcl.extend(
@@ -104,20 +105,19 @@ class StructCCode(Struct):
                 dcl.extend(
                     entry.AddDeclaration('(*%s_add)' % entry.Name()))
             self.PrintIndented(file, '  ', dcl)
-        print >>file, '};\n'
+        print('};\n', file=file)
 
-        print >>file, 'struct %s {' % self._name
-        print >>file, '  struct %s_access_ *base;\n' % self._name
+        print('struct %s {' % self._name, file=file)
+        print('  struct %s_access_ *base;\n' % self._name, file=file)
         for entry in self._entries:
             dcl = entry.Declaration()
             self.PrintIndented(file, '  ', dcl)
-        print >>file, ''
+        print('', file=file)
         for entry in self._entries:
-            print >>file, '  ev_uint8_t %s_set;' % entry.Name()
-        print >>file, '};\n'
+            print('  ev_uint8_t %s_set;' % entry.Name(), file=file)
+        print('};\n', file=file)
 
-        print >>file, \
-"""struct %(name)s *%(name)s_new(void);
+        print("""struct %(name)s *%(name)s_new(void);
 struct %(name)s *%(name)s_new_with_arg(void *);
 void %(name)s_free(struct %(name)s *);
 void %(name)s_clear(struct %(name)s *);
@@ -127,7 +127,7 @@ int %(name)s_complete(struct %(name)s *);
 void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
     const struct %(name)s *);
 int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
-    struct %(name)s *);""" % { 'name' : self._name }
+    struct %(name)s *);""" % { 'name' : self._name }, file=file)
 
 
         # Write a setting function of every variable
@@ -140,22 +140,21 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
                 self.PrintIndented(file, '', entry.AddDeclaration(
                     entry.AddFuncName()))
 
-        print >>file, '/* --- %s done --- */\n' % self._name
+        print('/* --- %s done --- */\n' % self._name, file=file)
 
     def PrintCode(self, file):
-        print >>file, ('/*\n'
+        print(('/*\n'
                        ' * Implementation of %s\n'
-                       ' */\n') % self._name
+                       ' */\n') % self._name, file=file)
 
-        print >>file, \
-              'static struct %(name)s_access_ __%(name)s_base = {' % \
-              { 'name' : self._name }
+        print('static struct %(name)s_access_ __%(name)s_base = {' % \
+              { 'name' : self._name }, file=file)
         for entry in self._entries:
             self.PrintIndented(file, '  ', entry.CodeBase())
-        print >>file, '};\n'
+        print('};\n', file=file)
 
         # Creation
-        print >>file, (
+        print((
             'struct %(name)s *\n'
             '%(name)s_new(void)\n'
             '{\n'
@@ -170,77 +169,77 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
             '    event_warn("%%s: malloc", __func__);\n'
             '    return (NULL);\n'
             '  }\n'
-            '  tmp->base = &__%(name)s_base;\n') % { 'name' : self._name }
+            '  tmp->base = &__%(name)s_base;\n') % { 'name' : self._name }, file=file)
 
         for entry in self._entries:
             self.PrintIndented(file, '  ', entry.CodeInitialize('tmp'))
-            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
+            print('  tmp->%s_set = 0;\n' % entry.Name(), file=file)
 
-        print >>file, (
+        print((
             '  return (tmp);\n'
-            '}\n')
+            '}\n'), file=file)
 
         # Adding
         for entry in self._entries:
             if entry.Array():
                 self.PrintIndented(file, '', entry.CodeAdd())
-            print >>file, ''
+            print('', file=file)
 
         # Assigning
         for entry in self._entries:
             self.PrintIndented(file, '', entry.CodeAssign())
-            print >>file, ''
+            print('', file=file)
 
         # Getting
         for entry in self._entries:
             self.PrintIndented(file, '', entry.CodeGet())
-            print >>file, ''
+            print('', file=file)
 
         # Clearing
-        print >>file, ( 'void\n'
+        print(( 'void\n'
                         '%(name)s_clear(struct %(name)s *tmp)\n'
                         '{'
-                        ) % { 'name' : self._name }
+                        ) % { 'name' : self._name }, file=file)
         for entry in self._entries:
             self.PrintIndented(file, '  ', entry.CodeClear('tmp'))
 
-        print >>file, '}\n'
+        print('}\n', file=file)
 
         # Freeing
-        print >>file, ( 'void\n'
+        print(( 'void\n'
                         '%(name)s_free(struct %(name)s *tmp)\n'
                         '{'
-                        ) % { 'name' : self._name }
+                        ) % { 'name' : self._name }, file=file)
 
         for entry in self._entries:
             self.PrintIndented(file, '  ', entry.CodeFree('tmp'))
 
-        print >>file, ('  free(tmp);\n'
-                       '}\n')
+        print(('  free(tmp);\n'
+                       '}\n'), file=file)
 
         # Marshaling
-        print >>file, ('void\n'
+        print(('void\n'
                        '%(name)s_marshal(struct evbuffer *evbuf, '
                        'const struct %(name)s *tmp)'
-                       '{') % { 'name' : self._name }
+                       '{') % { 'name' : self._name }, file=file)
         for entry in self._entries:
             indent = '  '
             # Optional entries do not have to be set
             if entry.Optional():
                 indent += '  '
-                print >>file, '  if (tmp->%s_set) {' % entry.Name()
+                print('  if (tmp->%s_set) {' % entry.Name(), file=file)
             self.PrintIndented(
                 file, indent,
                 entry.CodeMarshal('evbuf', self.EntryTagName(entry),
                                   entry.GetVarName('tmp'),
                                   entry.GetVarLen('tmp')))
             if entry.Optional():
-                print >>file, '  }'
+                print('  }', file=file)
 
-        print >>file, '}\n'
+        print('}\n', file=file)
 
         # Unmarshaling
-        print >>file, ('int\n'
+        print(('int\n'
                        '%(name)s_unmarshal(struct %(name)s *tmp, '
                        ' struct evbuffer *evbuf)\n'
                        '{\n'
@@ -249,14 +248,14 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
                        '    if (evtag_peek(evbuf, &tag) == -1)\n'
                        '      return (-1);\n'
                        '    switch (tag) {\n'
-                       ) % { 'name' : self._name }
+                       ) % { 'name' : self._name }, file=file)
         for entry in self._entries:
-            print >>file, '      case %s:\n' % self.EntryTagName(entry)
+            print('      case %s:\n' % self.EntryTagName(entry), file=file)
             if not entry.Array():
-                print >>file, (
+                print((
                     '        if (tmp->%s_set)\n'
                     '          return (-1);'
-                    ) % (entry.Name())
+                    ) % (entry.Name()), file=file)
 
             self.PrintIndented(
                 file, '        ',
@@ -265,26 +264,26 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
                                     entry.GetVarName('tmp'),
                                     entry.GetVarLen('tmp')))
 
-            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
-                            '        break;\n' )
-        print >>file, ( '      default:\n'
+            print(( '        tmp->%s_set = 1;\n' % entry.Name() +
+                            '        break;\n' ), file=file)
+        print(( '      default:\n'
                         '        return -1;\n'
                         '    }\n'
-                        '  }\n' )
+                        '  }\n' ), file=file)
         # Check if it was decoded completely
-        print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n'
+        print(( '  if (%(name)s_complete(tmp) == -1)\n'
                         '    return (-1);'
-                        ) % { 'name' : self._name }
+                        ) % { 'name' : self._name }, file=file)
 
         # Successfully decoded
-        print >>file, ( '  return (0);\n'
-                        '}\n')
+        print(( '  return (0);\n'
+                        '}\n'), file=file)
 
         # Checking if a structure has all the required data
-        print >>file, (
+        print((
             'int\n'
             '%(name)s_complete(struct %(name)s *msg)\n'
-            '{' ) % { 'name' : self._name }
+            '{' ) % { 'name' : self._name }, file=file)
         for entry in self._entries:
             if not entry.Optional():
                 code = [
@@ -297,12 +296,12 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
             self.PrintIndented(
                 file, '  ',
                 entry.CodeComplete('msg', entry.GetVarName('msg')))
-        print >>file, (
+        print((
             '  return (0);\n'
-            '}\n' )
+            '}\n' ), file=file)
 
         # Complete message unmarshaling
-        print >>file, (
+        print((
             'int\n'
             'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
             'ev_uint32_t need_tag, struct %(name)s *msg)\n'
@@ -324,10 +323,10 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
             ' error:\n'
             '  evbuffer_free(tmp);\n'
             '  return (res);\n'
-            '}\n' ) % { 'name' : self._name }
+            '}\n' ) % { 'name' : self._name }, file=file)
 
         # Complete message marshaling
-        print >>file, (
+        print((
             'void\n'
             'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
             'const struct %(name)s *msg)\n'
@@ -337,7 +336,7 @@ int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
             '  %(name)s_marshal(_buf, msg);\n'
             '  evtag_marshal_buffer(evbuf, tag, _buf);\n '
             '  evbuffer_free(_buf);\n'
-            '}\n' ) % { 'name' : self._name }
+            '}\n' ) % { 'name' : self._name }, file=file)
 
 class Entry:
     def __init__(self, type, name, tag):
@@ -1121,7 +1120,7 @@ class EntryArray(Entry):
 
         codearrayassign = self._entry.CodeArrayAssign(
             'msg->%(name)s_data[off]' % self.GetTranslation(), 'value')
-        code += map(lambda x: '    ' + x, codearrayassign)
+        code += ['    ' + x for x in codearrayassign]
 
         code += TranslateList([
             '  }',
@@ -1162,7 +1161,7 @@ class EntryArray(Entry):
 
         code = TranslateList(code, self.GetTranslation())
 
-        code += map(lambda x: '  ' + x, codearrayadd)
+        code += ['  ' + x for x in codearrayadd]
 
         code += TranslateList([
             '  msg->%(name)s_set = 1;',
@@ -1190,7 +1189,7 @@ class EntryArray(Entry):
 
         code = TranslateList(code, translate)
 
-        code += map(lambda x: '    ' + x, tmp)
+        code += ['    ' + x for x in tmp]
 
         code += [
             '  }',
@@ -1255,7 +1254,7 @@ class EntryArray(Entry):
         code = TranslateList(code, translate)
 
         if codearrayfree:
-            code += map(lambda x: '    ' + x, codearrayfree)
+            code += ['    ' + x for x in codearrayfree]
             code += [
                 '  }' ]
 
@@ -1668,31 +1667,31 @@ class CommandLine:
         impl_file = self.impl_file
         factory = self.factory
 
-        print >>sys.stderr, 'Reading \"%s\"' % filename
+        print('Reading \"%s\"' % filename, file=sys.stderr)
 
         fp = open(filename, 'r')
         entities = Parse(factory, fp)
         fp.close()
 
-        print >>sys.stderr, '... creating "%s"' % header_file
+        print('... creating "%s"' % header_file, file=sys.stderr)
         header_fp = open(header_file, 'w')
-        print >>header_fp, factory.HeaderPreamble(filename)
+        print(factory.HeaderPreamble(filename), file=header_fp)
 
         # Create forward declarations: allows other structs to reference
         # each other
         for entry in entities:
             entry.PrintForwardDeclaration(header_fp)
-        print >>header_fp, ''
+        print('', file=header_fp)
 
         for entry in entities:
             entry.PrintTags(header_fp)
             entry.PrintDeclaration(header_fp)
-        print >>header_fp, factory.HeaderPostamble(filename)
+        print(factory.HeaderPostamble(filename), file=header_fp)
         header_fp.close()
 
-        print >>sys.stderr, '... creating "%s"' % impl_file
+        print('... creating "%s"' % impl_file, file=sys.stderr)
         impl_fp = open(impl_file, 'w')
-        print >>impl_fp, factory.BodyPreamble(filename, header_file)
+        print(factory.BodyPreamble(filename, header_file), file=impl_fp)
         for entry in entities:
             entry.PrintCode(impl_fp)
         impl_fp.close()
@@ -1702,16 +1701,16 @@ if __name__ == '__main__':
         CommandLine(sys.argv).run()
         sys.exit(0)
 
-    except RpcGenError, e:
-        print >>sys.stderr, e
+    except RpcGenError as e:
+        print(e, file=sys.stderr)
         sys.exit(1)
 
-    except EnvironmentError, e:
+    except EnvironmentError as e:
         if e.filename and e.strerror:
-            print >>sys.stderr, "%s: %s" % (e.filename, e.strerror)
+            print("%s: %s" % (e.filename, e.strerror), file=sys.stderr)
             sys.exit(1)
         elif e.strerror:
-            print >> sys.stderr, e.strerror
+            print(e.strerror, file=sys.stderr)
             sys.exit(1)
         else:
             raise
diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py
index 2220b4f837..01a39bb195 100755
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -2,8 +2,9 @@
 # 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 print_function
 import optparse, os, re, sys
-from cStringIO import StringIO
+from io import StringIO
 from mozbuild.pythonutil import iter_modules_in_path
 import mozpack.path as mozpath
 import itertools
@@ -12,7 +13,7 @@ import ipdl
 
 def log(minv, fmt, *args):
     if _verbosity >= minv:
-        print fmt % args
+        print(fmt % args)
 
 # process command line
 
@@ -69,7 +70,7 @@ for (path, dirs, headers) in os.walk(headersdir):
         base = os.path.basename(h)
         if base in headersmap:
             root, ext = os.path.splitext(base)
-            print >>sys.stderr, 'A protocol named', root, 'exists in multiple namespaces'
+            print('A protocol named', root, 'exists in multiple namespaces', file=sys.stderr)
             sys.exit(1)
         headersmap[base] = os.path.join(path, h)
 
@@ -127,12 +128,12 @@ for f in files:
 
     ast = ipdl.parse(specstring, filename, includedirs=includedirs)
     if ast is None:
-        print >>sys.stderr, 'Specification could not be parsed.'
+        print('Specification could not be parsed.', file=sys.stderr)
         sys.exit(1)
 
     log(2, 'checking types')
     if not ipdl.typecheck(ast):
-        print >>sys.stderr, 'Specification is not well typed.'
+        print('Specification is not well typed.', file=sys.stderr)
         sys.exit(1)
 
     if _verbosity > 2:
@@ -154,30 +155,30 @@ allprotocols.sort()
 
 ipcmsgstart = StringIO()
 
-print >>ipcmsgstart, """
+print("""
 // CODE GENERATED by ipdl.py. Do not edit.
 
 #ifndef IPCMessageStart_h
 #define IPCMessageStart_h
 
 enum IPCMessageStart {
-"""
+""", file=ipcmsgstart)
 
 for name in allprotocols:
-    print >>ipcmsgstart, "  %s," % name
-    print >>ipcmsgstart, "  %sChild," % name
+    print("  %s," % name, file=ipcmsgstart)
+    print("  %sChild," % name, file=ipcmsgstart)
 
-print >>ipcmsgstart, """
+print("""
   LastMsgIndex
 };
 
 static_assert(LastMsgIndex <= 65536, "need to update IPC_MESSAGE_MACRO");
 
 #endif // ifndef IPCMessageStart_h
-"""
+""", file=ipcmsgstart)
 
 ipc_msgtype_name = StringIO()
-print >>ipc_msgtype_name, """
+print("""
 // CODE GENERATED by ipdl.py. Do not edit.
 #include <cstdint>
 
@@ -188,16 +189,16 @@ using std::uint32_t;
 namespace {
 
 enum IPCMessages {
-"""
+""", file=ipc_msgtype_name)
 
 for protocol in sorted(allmessages.keys()):
     for (msg, num) in allmessages[protocol].idnums:
         if num:
-            print >>ipc_msgtype_name, "  %s = %s," % (msg, num)
+            print("  %s = %s," % (msg, num), file=ipc_msgtype_name)
         elif not msg.endswith('End'):
-            print >>ipc_msgtype_name,  "  %s__%s," % (protocol, msg)
+            print("  %s__%s," % (protocol, msg), file=ipc_msgtype_name)
 
-print >>ipc_msgtype_name, """
+print("""
 };
 
 } // anonymous namespace
@@ -208,17 +209,17 @@ namespace ipc {
 const char* StringFromIPCMessageType(uint32_t aMessageType)
 {
   switch (aMessageType) {
-"""
+""", file=ipc_msgtype_name)
 
 for protocol in sorted(allmessages.keys()):
     for (msg, num) in allmessages[protocol].idnums:
         if num or msg.endswith('End'):
             continue
-        print >>ipc_msgtype_name, """
+        print("""
   case %s__%s:
-    return "%s::%s";""" % (protocol, msg, protocol, msg)
+    return "%s::%s";""" % (protocol, msg, protocol, msg), file=ipc_msgtype_name)
 
-print >>ipc_msgtype_name, """
+print("""
   default:
     return "???";
   }
@@ -226,7 +227,7 @@ print >>ipc_msgtype_name, """
 
 } // namespace ipc
 } // namespace mozilla
-"""
+""", file=ipc_msgtype_name)
 
 ipdl.writeifmodified(ipcmsgstart.getvalue(), ipcmessagestartpath)
 ipdl.writeifmodified(ipc_msgtype_name.getvalue(), ipc_msgtype_name_path)
diff --git a/ipc/ipdl/ipdl/__init__.py b/ipc/ipdl/ipdl/__init__.py
index d2d883f861..5d169d422a 100644
--- a/ipc/ipdl/ipdl/__init__.py
+++ b/ipc/ipdl/ipdl/__init__.py
@@ -5,7 +5,7 @@
 __all__ = [ 'gencxx', 'genipdl', 'parse', 'typecheck', 'writeifmodified' ]
 
 import os, sys
-from cStringIO import StringIO
+from io import StringIO
 
 from ipdl.cgen import IPDLCodeGen
 from ipdl.lower import LowerToCxx, msgenums
@@ -68,10 +68,10 @@ def writeifmodified(contents, file):
 
     oldcontents = None
     if os.path.exists(file):
-        fd = open(file, 'rb')
+        fd = open(file, 'r')
         oldcontents = fd.read()
         fd.close()
     if oldcontents != contents:
-        fd = open(file, 'wb')
+        fd = open(file, 'w')
         fd.write(contents)
         fd.close()
diff --git a/ipc/ipdl/ipdl/ast.py b/ipc/ipdl/ipdl/ast.py
index a8bd1e41f7..66cbb130e3 100644
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -13,8 +13,8 @@ HIGH_PRIORITY = 2
 
 class Visitor:
     def defaultVisit(self, node):
-        raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
-            node.__class__.__name__)
+        raise Exception("INTERNAL ERROR: no visitor for node type `%s'"% (
+            node.__class__.__name__))
 
     def visitTranslationUnit(self, tu):
         for cxxInc in tu.cxxIncludes:
@@ -320,7 +320,7 @@ class MessageDecl(Node):
             elif modifier == 'verify':
                 self.verify = modifier
             elif modifier != '':
-                raise Exception, "Unexpected message modifier `%s'"% modifier
+                raise Exception("Unexpected message modifier `%s'"% modifier)
 
 class Transition(Node):
     def __init__(self, loc, trigger, msg, toStates):
diff --git a/ipc/ipdl/ipdl/cxx/ast.py b/ipc/ipdl/ipdl/cxx/ast.py
index 18c2b3f1db..125942f47e 100644
--- a/ipc/ipdl/ipdl/cxx/ast.py
+++ b/ipc/ipdl/ipdl/cxx/ast.py
@@ -3,11 +3,12 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import copy, sys
+from functools import reduce
 
 class Visitor:
     def defaultVisit(self, node):
-        raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
-            node.__class__.__name__)
+        raise Exception("INTERNAL ERROR: no visitor for node type `%s'"% (
+            node.__class__.__name__))
 
     def visitWhitespace(self, ws):
         pass
@@ -375,11 +376,11 @@ class Typedef(Node):
         self.totypename = totypename
         self.templateargs = templateargs
 
-    def __cmp__(self, o):
-        return cmp(self.totypename, o.totypename)
+    def __lt__(self, o):
+        return self.totypename < o.totypename
     def __eq__(self, o):
         return (self.__class__ == o.__class__
-                and 0 == cmp(self, o))
+                and self.totypename == o.totypename)
     def __hash__(self):
         return hash(self.totypename)
 
diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py
index 61855a7a9e..4b373fda7d 100644
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1730,7 +1730,7 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
                 transitions.append(ifsametrigger)
                 msgToTransitions[msgid] = transitions
 
-            for msgid, transitions in msgToTransitions.iteritems():
+            for msgid, transitions in msgToTransitions.items():
                 block = Block()
                 block.addstmts(transitions +[ StmtBreak() ])
                 msgswitch.addcase(CaseLabel(msgid), block)
diff --git a/ipc/ipdl/ipdl/parser.py b/ipc/ipdl/ipdl/parser.py
index 38c46dc73a..6cb99163a5 100644
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os, sys
 from ply import lex, yacc
 
@@ -78,8 +79,8 @@ class Parser:
         try:
             ast = self.parser.parse(input=input, lexer=self.lexer,
                                     debug=self.debug)
-        except ParseError, p:
-            print >>errout, p
+        except ParseError as p:
+            print(p, file=errout)
             return None
 
         Parser.current = Parser.parseStack.pop()
@@ -648,7 +649,7 @@ def p_Nested(p):
     if p[1] not in kinds:
         _error(locFromTok(p, 1), "Expected not, inside_sync, or inside_cpow for nested()")
 
-    p[0] = { 'nested': kinds[p[1]] }
+    p[0] = kinds[p[1]]
 
 def p_Priority(p):
     """Priority : ID"""
@@ -662,7 +663,10 @@ def p_Priority(p):
 def p_SendQualifier(p):
     """SendQualifier : NESTED '(' Nested ')'
                      | PRIO '(' Priority ')'"""
-    p[0] = p[3]
+    if p[1] == 'nested':
+        p[0] = {'nested': p[3]}
+    else:
+        p[0] = p[3]
 
 def p_SendQualifierList(p):
     """SendQualifierList : SendQualifier SendQualifierList
diff --git a/ipc/ipdl/ipdl/type.py b/ipc/ipdl/ipdl/type.py
index 66a9fbd3ff..a6e8dbd845 100644
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os, sys
 
 from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt
@@ -10,6 +11,7 @@ from ipdl.ast import ASYNC, SYNC, INTR
 from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
 from ipdl.ast import NOT_NESTED, INSIDE_SYNC_NESTED, INSIDE_CPOW_NESTED
 import ipdl.builtin as builtin
+from functools import reduce
 
 _DELETE_MSG = '__delete__'
 
@@ -22,7 +24,7 @@ def _otherside(side):
 def unique_pairs(s):
     n = len(s)
     for i, e1 in enumerate(s):
-        for j in xrange(i+1, n):
+        for j in range(i+1, n):
             yield (e1, s[j])
 
 def cartesian_product(s1, s2):
@@ -36,8 +38,8 @@ class TypeVisitor:
         self.visited = set()
 
     def defaultVisit(self, node, *args):
-        raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
-            node.__class__.__name__)
+        raise Exception("INTERNAL ERROR: no visitor for node type `%s'"% (
+            node.__class__.__name__))
 
     def visitVoidType(self, v, *args):
         pass
@@ -125,8 +127,8 @@ class Type:
     def typename(self):
         return self.__class__.__name__
 
-    def name(self): raise Exception, 'NYI'
-    def fullname(self): raise Exception, 'NYI'
+    def name(self): raise Exception('NYI')
+    def fullname(self): raise Exception('NYI')
 
     def accept(self, visitor, *args):
         visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
@@ -506,7 +508,7 @@ def hasactor(type):
 
 def hasshmem(type):
     """Return true iff |type| is shmem or has it buried within."""
-    class found: pass
+    class found(Exception): pass
     class findShmem(TypeVisitor):
         def visitShmemType(self, s):  raise found()
     try:
@@ -517,7 +519,7 @@ def hasshmem(type):
 
 def hasfd(type):
     """Return true iff |type| is fd or has it buried within."""
-    class found: pass
+    class found(Exception): pass
     class findFD(TypeVisitor):
         def visitFDType(self, s):  raise found()
     try:
@@ -647,7 +649,7 @@ With this information, it finally type checks the AST.'''
 
     def reportErrors(self, errout):
         for error in self.errors:
-            print >>errout, error
+            print(error, file=errout)
 
 
 class TcheckVisitor(Visitor):
@@ -1581,7 +1583,7 @@ class Process:
         self.spawn.add(spawn)
 
     def iteredges(self):
-        for edgelist in self.edges.itervalues():
+        for edgelist in self.edges.values():
             for edge in edgelist:
                 yield edge
 
@@ -1690,7 +1692,7 @@ class ProcessGraph:
 
     @classmethod
     def iterbridges(cls):
-        for edges in cls.bridges.itervalues():
+        for edges in cls.bridges.values():
             for bridge in edges:
                 yield bridge
 
@@ -1711,7 +1713,7 @@ class ProcessGraph:
 
     @classmethod
     def iteropens(cls):
-        for edges in cls.opens.itervalues():
+        for edges in cls.opens.values():
             for opens in edges:
                 yield opens
 
@@ -1879,19 +1881,19 @@ class CheckProcessGraph(TcheckVisitor):
     # is a dag
     def visitTranslationUnit(self, tu):
         if 0:
-            print 'Processes'
+            print('Processes')
             for process in ProcessGraph.processes:
-                print '  ', process
+                print('  ', process)
                 for edge in process.iteredges():
-                    print '    ', edge
-            print 'Bridges'
-            for bridgeList in ProcessGraph.bridges.itervalues():
+                    print('    ', edge)
+            print('Bridges')
+            for bridgeList in ProcessGraph.bridges.values():
                 for bridge in bridgeList:
-                    print '  ', bridge
-            print 'Opens'
-            for opensList in ProcessGraph.opens.itervalues():
+                    print('  ', bridge)
+            print('Opens')
+            for opensList in ProcessGraph.opens.values():
                 for opens in opensList:
-                    print '  ', opens
+                    print('  ', opens)
 
 ##-----------------------------------------------------------------------------
 
@@ -2088,19 +2090,19 @@ direction as trigger |t|'''
                 errT2 = None
 
                 if 0 == len(U1) or 0 == len(U2):
-                    print "******* case 1"
+                    print("******* case 1")
                     raceError = True
                 elif 1 < len(U1) or 1 < len(U2):
                     raceError = True
                     # there are potentially many unpaired states; just
                     # pick two
-                    print "******* case 2"
+                    print("******* case 2")
                     for u1, u2 in cartesian_product(U1, U2):
                         if u1 != u2:
                             errT1, errT2 = u1, u2
                             break
                 elif U1 != U2:
-                    print "******* case 3"
+                    print("******* case 3")
                     raceError = True
                     for errT1 in U1: pass
                     for errT2 in U2: pass
@@ -2140,7 +2142,7 @@ direction as trigger |t|'''
                     root.loc,
                     "when starting from state `%s', actors of protocol `%s' cannot be deleted", root.state.name, p.name)
 
-        for ts in p.states.itervalues():
+        for ts in p.states.values():
             if ts.state is not State.DEAD and ts.state not in allvisited:
                 self.error(ts.loc,
                            "unreachable state `%s' in protocol `%s'",
diff --git a/ipc/ipdl/test/cxx/genIPDLUnitTests.py b/ipc/ipdl/test/cxx/genIPDLUnitTests.py
index 24026451bc..e1c29798b2 100644
--- a/ipc/ipdl/test/cxx/genIPDLUnitTests.py
+++ b/ipc/ipdl/test/cxx/genIPDLUnitTests.py
@@ -2,10 +2,11 @@
 # 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 print_function
 import string, sys
 
 def usage():
-    print >>sys.stderr, """
+    print("""
 %s template_file -t unit_tests... -e extra_protocols...
 
   TEMPLATE_FILE is used to generate to generate the unit-tester .cpp
@@ -13,7 +14,7 @@ def usage():
   EXTRA_PROTOCOLS are top-level protocols for subprocesses that can be
                   spawned in tests but are not unit tests in and of
                   themselves
-"""% (sys.argv[0])
+"""% (sys.argv[0]), file=sys.stderr)
     sys.exit(1)
 
 def main(argv):
diff --git a/ipc/pull-chromium.py b/ipc/pull-chromium.py
index c4a476e425..114360ca31 100644
--- a/ipc/pull-chromium.py
+++ b/ipc/pull-chromium.py
@@ -12,6 +12,7 @@ http://dev.chromium.org/developers/how-tos/get-the-code for details about
 doing this efficiently.
 """
 
+from __future__ import print_function
 import sys, os
 from subprocess import check_call
 from shutil import rmtree
@@ -19,11 +20,11 @@ from shutil import rmtree
 topsrcdir, chromiumtree, rev = sys.argv[1:]
 
 if not os.path.exists(os.path.join(topsrcdir, 'client.py')):
-    print >>sys.stderr, "Incorrect topsrcdir"
+    print("Incorrect topsrcdir", file=sys.stderr)
     sys.exit(1)
 
 if not os.path.exists(os.path.join(chromiumtree, 'src/DEPS')):
-    print >>sys.stderr, "Incorrect chromium directory, missing DEPS"
+    print("Incorrect chromium directory, missing DEPS", file=sys.stderr)
     sys.exit(1)
 
 check_call(['gclient', 'sync', '--force', '--revision=src@%s' % rev], cwd=chromiumtree)
diff --git a/js/src/builtin/embedjs.py b/js/src/builtin/embedjs.py
index c642aebd51..87a269259e 100644
--- a/js/src/builtin/embedjs.py
+++ b/js/src/builtin/embedjs.py
@@ -37,6 +37,7 @@
 # It uses the C preprocessor to process its inputs.
 
 from __future__ import with_statement
+from __future__ import print_function
 import re, sys, os, subprocess
 import shlex
 import which
@@ -53,7 +54,7 @@ def ToCAsciiArray(lines):
 def ToCArray(lines):
   result = []
   for chr in lines:
-    result.append(str(ord(chr)))
+    result.append(str(chr if isinstance(chr, int) else ord(chr)))
   return ", ".join(result)
 
 HEADER_TEMPLATE = """\
@@ -87,7 +88,7 @@ def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, namespace, env)
 
   js_out.write(processed)
   import zlib
-  compressed = zlib.compress(processed)
+  compressed = zlib.compress(processed.encode('utf-8'))
   data = ToCArray(compressed)
   c_out.write(HEADER_TEMPLATE % {
     'sources_type': 'unsigned char',
@@ -107,9 +108,9 @@ def preprocess(cxx, preprocessorOption, source, args = []):
   tmpOut = 'self-hosting-preprocessed.pp';
   outputArg = shlex.split(preprocessorOption + tmpOut)
 
-  with open(tmpIn, 'wb') as input:
+  with open(tmpIn, 'w') as input:
     input.write(source)
-  print(' '.join(cxx + outputArg + args + [tmpIn]))
+  print((' '.join(cxx + outputArg + args + [tmpIn])))
   result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
   if (result != 0):
     sys.exit(result);
@@ -132,7 +133,7 @@ def messages(jsmsg):
 
 def get_config_defines(buildconfig):
   # Collect defines equivalent to ACDEFINES and add MOZ_DEBUG_DEFINES.
-  env = {key: value for key, value in buildconfig.defines.iteritems()
+  env = {key: value for key, value in buildconfig.defines.items()
          if key not in buildconfig.non_global_defines}
   for define in buildconfig.substs['MOZ_DEBUG_DEFINES']:
     env[define] = 1
diff --git a/js/src/builtin/intl/make_intl_data.py b/js/src/builtin/intl/make_intl_data.py
index 7cd4b2c652..fb6db50b88 100644
--- a/js/src/builtin/intl/make_intl_data.py
+++ b/js/src/builtin/intl/make_intl_data.py
@@ -31,20 +31,23 @@ import codecs
 import sys
 import tarfile
 import tempfile
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 from contextlib import closing
 from functools import partial
-from itertools import chain, ifilter, ifilterfalse, imap, izip_longest, groupby, tee
+from itertools import chain, groupby, tee
 from operator import attrgetter, itemgetter
-from urlparse import urlsplit
+from urllib.parse import urlsplit
 from zipfile import ZipFile
+import six
+from six.moves import filterfalse
+from itertools import zip_longest
 
 # From https://docs.python.org/3/library/itertools.html
 def grouper(iterable, n, fillvalue=None):
     "Collect data into fixed-length chunks or blocks"
     # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
     args = [iter(iterable)] * n
-    return izip_longest(*args, fillvalue=fillvalue)
+    return zip_longest(*args, fillvalue=fillvalue)
 
 def writeMappingHeader(println, description, source, url):
     if type(description) is not list:
@@ -64,7 +67,7 @@ def writeMappingsVar(println, mapping, name, description, source, url):
     println(u"")
     writeMappingHeader(println, description, source, url)
     println(u"var {0} = {{".format(name))
-    for (key, value) in sorted(mapping.items(), key=itemgetter(0)):
+    for (key, value) in sorted(list(mapping.items()), key=itemgetter(0)):
         println(u'    "{0}": "{1}",'.format(key, value))
     println(u"};")
 
@@ -103,7 +106,7 @@ bool js::intl::LanguageTag::{0}({1} {2}) {{
     # Sort the subtags by length. That enables using an optimized comparator
     # for the binary search, which only performs a single |memcmp| for multiple
     # of two subtag lengths.
-    mappings_keys = mappings.keys() if type(mappings) == dict else mappings
+    mappings_keys = list(mappings.keys()) if type(mappings) == dict else mappings
     for (length, subtags) in groupby(sorted(mappings_keys, key=len), len):
         # Omit the length check if the current length is the maximum length.
         if length != tag_maxlength:
@@ -198,7 +201,7 @@ void js::intl::LanguageTag::performComplexLanguageMappings() {
     # Merge duplicate language entries.
     language_aliases = {}
     for (deprecated_language, (language, script, region)) in (
-        sorted(complex_language_mappings.items(), key=itemgetter(0))
+        sorted(list(complex_language_mappings.items()), key=itemgetter(0))
     ):
         key = (language, script, region)
         if key not in language_aliases:
@@ -208,7 +211,7 @@ void js::intl::LanguageTag::performComplexLanguageMappings() {
 
     first_language = True
     for (deprecated_language, (language, script, region)) in (
-        sorted(complex_language_mappings.items(), key=itemgetter(0))
+        sorted(list(complex_language_mappings.items()), key=itemgetter(0))
     ):
         key = (language, script, region)
         if deprecated_language in language_aliases[key]:
@@ -265,7 +268,7 @@ void js::intl::LanguageTag::performComplexRegionMappings() {
     # Merge duplicate region entries.
     region_aliases = {}
     for (deprecated_region, (default, non_default_replacements)) in (
-        sorted(complex_region_mappings.items(), key=itemgetter(0))
+        sorted(list(complex_region_mappings.items()), key=itemgetter(0))
     ):
         key = hash_key(default, non_default_replacements)
         if key not in region_aliases:
@@ -275,7 +278,7 @@ void js::intl::LanguageTag::performComplexRegionMappings() {
 
     first_region = True
     for (deprecated_region, (default, non_default_replacements)) in (
-        sorted(complex_region_mappings.items(), key=itemgetter(0))
+        sorted(list(complex_region_mappings.items()), key=itemgetter(0))
     ):
         key = hash_key(default, non_default_replacements)
         if deprecated_region in region_aliases[key]:
@@ -380,7 +383,7 @@ bool js::intl::LanguageTag::performVariantMappings(JSContext* cx) {
     first_variant = True
 
     for (deprecated_variant, (type, replacement)) in (
-        sorted(variant_mappings.items(), key=itemgetter(0))
+        sorted(list(variant_mappings.items()), key=itemgetter(0))
     ):
         if_kind = u"if" if first_variant else u"else if"
         first_variant = False
@@ -498,7 +501,7 @@ bool js::intl::LanguageTag::updateGrandfatheredMappings(JSContext* cx) {
 
     is_first = True
 
-    for (tag, modern) in sorted(grandfathered_mappings.items(), key=itemgetter(0)):
+    for (tag, modern) in sorted(list(grandfathered_mappings.items()), key=itemgetter(0)):
         tag_match = re_unicode_locale_id.match(tag)
         assert tag_match is not None
 
@@ -1152,7 +1155,7 @@ static bool IsCanonicallyCasedTransformType(mozilla::Span<const char> type) {
                               "const LanguageSubtag&", "language",
                               "IsStructurallyValidLanguageTag",
                               "IsCanonicallyCasedLanguageTag",
-                              complex_language_mappings.keys(), language_maxlength,
+                              list(complex_language_mappings.keys()), language_maxlength,
                               "Language subtags with complex mappings.", source, url)
     writeMappingsBinarySearch(println, "regionMapping",
                               "RegionSubtag&", "region",
@@ -1164,7 +1167,7 @@ static bool IsCanonicallyCasedTransformType(mozilla::Span<const char> type) {
                               "const RegionSubtag&", "region",
                               "IsStructurallyValidRegionTag",
                               "IsCanonicallyCasedRegionTag",
-                              complex_region_mappings.keys(), region_maxlength,
+                              list(complex_region_mappings.keys()), region_maxlength,
                               "Region subtags with complex mappings.", source, url)
 
     writeComplexLanguageTagMappings(println, complex_language_mappings,
@@ -1360,7 +1363,7 @@ def updateCLDRLangTags(args):
             readFiles(cldr_file)
     else:
         print("Downloading CLDR core.zip...")
-        with closing(urllib2.urlopen(url)) as cldr_file:
+        with closing(six.moves.urllib.request.urlopen(url)) as cldr_file:
             cldr_data = io.BytesIO(cldr_file.read())
             readFiles(cldr_data)
 
@@ -1435,20 +1438,20 @@ class TzDataFile:
 
 def validateTimeZones(zones, links):
     """ Validate the zone and link entries. """
-    linkZones = set(links.viewkeys())
+    linkZones = set(six.viewkeys(links))
     intersect = linkZones.intersection(zones)
     if intersect:
         raise RuntimeError("Links also present in zones: %s" % intersect)
 
     zoneNames = set(z.name for z in zones)
-    linkTargets = set(links.viewvalues())
+    linkTargets = set(six.viewvalues(links))
     if not linkTargets.issubset(zoneNames):
         raise RuntimeError("Link targets not found: %s" % linkTargets.difference(zoneNames))
 
 def partition(iterable, *predicates):
     def innerPartition(pred, it):
         it1, it2 = tee(it)
-        return (ifilter(pred, it1), ifilterfalse(pred, it2))
+        return (filter(pred, it1), filterfalse(pred, it2))
     if len(predicates) == 0:
         return iterable
     (left, right) = innerPartition(predicates[0], iterable)
@@ -1459,7 +1462,7 @@ def partition(iterable, *predicates):
 def listIANAFiles(tzdataDir):
     def isTzFile(d, m, f):
         return m(f) and d.isfile(d.resolve(f))
-    return ifilter(partial(isTzFile, tzdataDir, re.compile("^[a-z0-9]+$").match), tzdataDir.listdir())
+    return filter(partial(isTzFile, tzdataDir, re.compile("^[a-z0-9]+$").match), tzdataDir.listdir())
 
 def readIANAFiles(tzdataDir, files):
     """ Read all IANA time zone files from the given iterable. """
@@ -1507,7 +1510,7 @@ def readIANATimeZones(tzdataDir, ignoreBackzone, ignoreFactory):
     # Merge with backzone data.
     if not ignoreBackzone:
         zones |= backzones
-        links = {name: target for name, target in links.iteritems() if name not in backzones}
+        links = {name: target for name, target in links.items() if name not in backzones}
         links.update(backlinks)
 
     validateTimeZones(zones, links)
@@ -1644,7 +1647,7 @@ def readICUTimeZonesFromZoneInfo(icuTzDir):
         elif name == namesKey:
             tzNames.extend(value)
 
-    links = dict((Zone(tzNames[zone]), tzNames[target]) for (zone, target) in tzLinks.iteritems())
+    links = dict((Zone(tzNames[zone]), tzNames[target]) for (zone, target) in tzLinks.items())
     zones = set([Zone(v) for v in tzNames if Zone(v) not in links])
 
     validateTimeZones(zones, links)
@@ -1685,7 +1688,7 @@ def readICUTimeZones(icuDir, icuTzDir, ignoreFactory):
     if notFoundInZoneInfo64:
         raise RuntimeError("Missing time zones in zoneinfo64.txt: %s" % notFoundInZoneInfo64)
 
-    notFoundInZoneInfo64 = [zone for zone in typesLinks.iterkeys() if not inZoneInfo64(zone)]
+    notFoundInZoneInfo64 = [zone for zone in typesLinks.keys() if not inZoneInfo64(zone)]
     if notFoundInZoneInfo64:
         raise RuntimeError("Missing time zones in zoneinfo64.txt: %s" % notFoundInZoneInfo64)
 
@@ -1697,8 +1700,8 @@ def readICUTimeZones(icuDir, icuTzDir, ignoreFactory):
                  (zone for zone in typesZones)
                ))
     icuLinks = dict(chain(
-                 ((zone, target) for (zone, target) in zoneinfoLinks.iteritems() if zone not in typesZones),
-                 ((zone, target) for (zone, target) in typesLinks.iteritems())
+                 ((zone, target) for (zone, target) in zoneinfoLinks.items() if zone not in typesZones),
+                 ((zone, target) for (zone, target) in typesLinks.items())
                ))
 
     return (icuZones, icuLinks)
@@ -1801,7 +1804,7 @@ def findIncorrectICUZones(ianaZones, ianaLinks, icuZones, icuLinks, ignoreBackzo
 
     # Remove unnecessary UTC mappings.
     utcnames = ["Etc/UTC", "Etc/UCT", "Etc/GMT"]
-    result = ifilterfalse(lambda (zone, target): zone.name in utcnames, result)
+    result = filterfalse(lambda zone_target1: zone_target1[0].name in utcnames, result)
 
     return sorted(result, key=itemgetter(0))
 
@@ -1813,28 +1816,28 @@ def findIncorrectICULinks(ianaZones, ianaLinks, icuZones, icuLinks):
     isICUZone = lambda zone: zone in icuZones
 
     # All links should be present in ICU.
-    missingTimeZones = [zone for zone in ianaLinks.iterkeys() if not isICUTimeZone(zone)]
+    missingTimeZones = [zone for zone in ianaLinks.keys() if not isICUTimeZone(zone)]
     if missingTimeZones:
         raise RuntimeError("Not all zones are present in ICU, did you forget "
                            "to run intl/update-tzdata.sh? %s" % missingTimeZones)
 
     # Links which are only present in ICU?
-    additionalTimeZones = [zone for zone in icuLinks.iterkeys() if not isIANATimeZone(zone)]
+    additionalTimeZones = [zone for zone in icuLinks.keys() if not isIANATimeZone(zone)]
     if additionalTimeZones:
         raise RuntimeError("Additional links present in ICU, did you forget "
                            "to run intl/update-tzdata.sh? %s" % additionalTimeZones)
 
     result = chain(
         # IANA links which have a different target in ICU.
-        ((zone, target, icuLinks[zone]) for (zone, target) in ianaLinks.iteritems() if isICULink(zone) and target != icuLinks[zone]),
+        ((zone, target, icuLinks[zone]) for (zone, target) in ianaLinks.items() if isICULink(zone) and target != icuLinks[zone]),
 
         # IANA links which are zones in ICU.
-        ((zone, target, zone.name) for (zone, target) in ianaLinks.iteritems() if isICUZone(zone))
+        ((zone, target, zone.name) for (zone, target) in ianaLinks.items() if isICUZone(zone))
     )
 
     # Remove unnecessary UTC mappings.
     utcnames = ["Etc/UTC", "Etc/UCT", "Etc/GMT"]
-    result = ifilterfalse(lambda (zone, target, icuTarget): target in utcnames and icuTarget in utcnames, result)
+    result = filterfalse(lambda zone_target_icuTarget: zone_target_icuTarget[1] in utcnames and zone_target_icuTarget[2] in utcnames, result)
 
     return sorted(result, key=itemgetter(0))
 
@@ -1919,16 +1922,16 @@ def processTimeZones(tzdataDir, icuDir, icuTzDir, version, ignoreBackzone, ignor
 def updateBackzoneLinks(tzdataDir, links):
     (backzoneZones, backzoneLinks) = readIANAFiles(tzdataDir, ["backzone"])
     (stableZones, updatedLinks, updatedZones) = partition(
-        links.iteritems(),
+        links.items(),
         # Link not changed in backzone.
-        lambda (zone, target): zone not in backzoneLinks and zone not in backzoneZones,
+        lambda zone_target2: zone_target2[0] not in backzoneLinks and zone_target2[0] not in backzoneZones,
         # Link has a new target.
-        lambda (zone, target): zone in backzoneLinks,
+        lambda zone_target3: zone_target3[0] in backzoneLinks,
     )
     # Keep stable zones and links with updated target.
     return dict(chain(
                 stableZones,
-                imap(lambda (zone, target): (zone, backzoneLinks[zone]), updatedLinks)
+                map(lambda zone_target: (zone_target[0], backzoneLinks[zone_target[0]]), updatedLinks)
            ))
 
 def generateTzDataLinkTestContent(testDir, version, fileName, description, links):
@@ -1981,11 +1984,11 @@ def generateTzDataTestBackwardLinks(tzdataDir, version, ignoreBackzone, testDir)
         testDir, version,
         "timeZone_backward_links.js",
         u"// Link names derived from IANA Time Zone Database, backward file.",
-        links.iteritems()
+        links.items()
     )
 
 def generateTzDataTestNotBackwardLinks(tzdataDir, version, ignoreBackzone, testDir):
-    tzfiles = ifilterfalse({"backward", "backzone"}.__contains__, listIANAFiles(tzdataDir))
+    tzfiles = filterfalse({"backward", "backzone"}.__contains__, listIANAFiles(tzdataDir))
     (zones, links) = readIANAFiles(tzdataDir, tzfiles)
 
     if not ignoreBackzone:
@@ -1995,7 +1998,7 @@ def generateTzDataTestNotBackwardLinks(tzdataDir, version, ignoreBackzone, testD
         testDir, version,
         "timeZone_notbackward_links.js",
         u"// Link names derived from IANA Time Zone Database, excluding backward file.",
-        links.iteritems()
+        links.items()
     )
 
 def generateTzDataTestBackzone(tzdataDir, version, ignoreBackzone, testDir):
@@ -2056,7 +2059,7 @@ def generateTzDataTestBackzoneLinks(tzdataDir, version, ignoreBackzone, testDir)
         testDir, version,
         "timeZone_backzone_links.js",
         comment +  u"// Backzone links derived from IANA Time Zone Database.",
-        ((zone, target if not ignoreBackzone else links[zone]) for (zone, target) in backlinks.iteritems())
+        ((zone, target if not ignoreBackzone else links[zone]) for (zone, target) in backlinks.items())
     )
 
 def generateTzDataTests(tzdataDir, version, ignoreBackzone, testDir):
@@ -2114,7 +2117,7 @@ def updateTzdata(topsrcdir, args):
 
     if tzDir is None:
         print("Downloading tzdata file...")
-        with closing(urllib2.urlopen(url)) as tzfile:
+        with closing(six.moves.urllib.request.urlopen(url)) as tzfile:
             fname = urlsplit(tzfile.geturl()).path.split("/")[-1]
             with tempfile.NamedTemporaryFile(suffix=fname) as tztmpfile:
                 print("File stored in %s" % tztmpfile.name)
@@ -2146,7 +2149,7 @@ static inline bool Is{0}Type(
 
     linear_search_max_length = 4
 
-    needs_binary_search = any(len(replacements.items()) > linear_search_max_length
+    needs_binary_search = any(len(list(replacements.items())) > linear_search_max_length
                               for replacements in mapping.values())
 
     if needs_binary_search:
@@ -2220,7 +2223,7 @@ const char* js::intl::LanguageTag::replace{0}ExtensionType(
 
     # Merge duplicate keys.
     key_aliases = {}
-    for (key, replacements) in sorted(mapping.items(), key=itemgetter(0)):
+    for (key, replacements) in sorted(list(mapping.items()), key=itemgetter(0)):
         hash_key = to_hash_key(replacements)
         if hash_key not in key_aliases:
             key_aliases[hash_key] = []
@@ -2228,7 +2231,7 @@ const char* js::intl::LanguageTag::replace{0}ExtensionType(
             key_aliases[hash_key].append(key)
 
     first_key = True
-    for (key, replacements) in sorted(mapping.items(), key=itemgetter(0)):
+    for (key, replacements) in sorted(list(mapping.items()), key=itemgetter(0)):
         hash_key = to_hash_key(replacements)
         if key in key_aliases[hash_key]:
             continue
@@ -2242,7 +2245,7 @@ const char* js::intl::LanguageTag::replace{0}ExtensionType(
   {} ({}) {{""".format(if_kind, cond).strip("\n"))
         first_key = False
 
-        replacements = sorted(replacements.items(), key=itemgetter(0))
+        replacements = sorted(list(replacements.items()), key=itemgetter(0))
 
         if len(replacements) > linear_search_max_length:
             types = [t for (t, _) in replacements]
diff --git a/js/src/ctypes/libffi/generate-darwin-source-and-headers.py b/js/src/ctypes/libffi/generate-darwin-source-and-headers.py
index 964e861d43..b53ce68c9c 100644
--- a/js/src/ctypes/libffi/generate-darwin-source-and-headers.py
+++ b/js/src/ctypes/libffi/generate-darwin-source-and-headers.py
@@ -194,7 +194,7 @@ def generate_source_and_headers(generate_osx=True, generate_ios=True):
         build_target(desktop64_platform, platform_headers)
 
     mkdir_p('darwin_common/include')
-    for header_name, tag_tuples in platform_headers.iteritems():
+    for header_name, tag_tuples in platform_headers.items():
         basename, suffix = os.path.splitext(header_name)
         with open(os.path.join('darwin_common/include', header_name), 'w') as header:
             for tag_tuple in tag_tuples:
diff --git a/js/src/devtools/automation/autospider.py b/js/src/devtools/automation/autospider.py
index 030d8c98d7..0d9366a87d 100755
--- a/js/src/devtools/automation/autospider.py
+++ b/js/src/devtools/automation/autospider.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import argparse
 import json
 import logging
@@ -106,7 +107,7 @@ def set_vars_from_script(script, vars):
                 var, value = m.groups()
                 if var in tograb:
                     env[var] = value
-                    print("Setting %s = %s" % (var, value))
+                    print(("Setting %s = %s" % (var, value)))
                 if var.startswith("ORIGINAL_"):
                     originals[var[9:]] = value
 
@@ -290,7 +291,7 @@ if not args.nobuild:
     configure = os.path.join(DIR.js_src, 'configure')
     if not os.path.exists(configure):
         shutil.copyfile(configure + ".in", configure)
-        os.chmod(configure, 0755)
+        os.chmod(configure, 0o755)
 
     # Run configure; make
     run_command(['sh', '-c', posixpath.join(PDIR.js_src, 'configure') + ' ' + CONFIGURE_ARGS], check=True)
@@ -359,11 +360,11 @@ if 'jstests' in test_suites:
 # FIXME bug 1291449: This would be unnecessary if we could run msan with -mllvm
 # -msan-keep-going, but in clang 3.8 it causes a hang during compilation.
 if variant.get('ignore-test-failures'):
-    print("Ignoring test results %s" % (results,))
+    print(("Ignoring test results %s" % (results,)))
     results = [0]
 
 if args.variant in ('tsan', 'msan'):
-    files = filter(lambda f: f.startswith("sanitize_log."), os.listdir(OUTDIR))
+    files = [f for f in os.listdir(OUTDIR) if f.startswith("sanitize_log.")]
     fullfiles = [os.path.join(OUTDIR, f) for f in files]
 
     # Summarize results
@@ -384,11 +385,11 @@ if args.variant in ('tsan', 'msan'):
     summary_filename = os.path.join(env['MOZ_UPLOAD_DIR'], "%s_summary.txt" % args.variant)
     with open(summary_filename, 'wb') as outfh:
         for location, count in sites.most_common():
-            print >> outfh, "%d %s" % (count, location)
-    print(open(summary_filename, 'rb').read())
+            print("%d %s" % (count, location), file=outfh)
+    print((open(summary_filename, 'rb').read()))
 
     if 'max-errors' in variant:
-        print("Found %d errors out of %d allowed" % (len(sites), variant['max-errors']))
+        print(("Found %d errors out of %d allowed" % (len(sites), variant['max-errors'])))
         if len(sites) > variant['max-errors']:
             results.append(1)
 
diff --git a/js/src/devtools/gc/gc-test.py b/js/src/devtools/gc/gc-test.py
index dd2097804a..09d78f1293 100644
--- a/js/src/devtools/gc/gc-test.py
+++ b/js/src/devtools/gc/gc-test.py
@@ -4,6 +4,7 @@
 
 # Works with python2.6
 
+from __future__ import print_function
 import datetime, os, re, sys, traceback
 import math, string, copy, json
 import subprocess
@@ -82,20 +83,20 @@ def run_tests(tests, test_dir):
             fmt = '%20s: {"TMax": %4.1f, "TAvg": %4.1f, "MMax": %4.1f, "MAvg": %4.1f, "SMax": %4.1f, "SAvg": %4.1f}'
             if (i != len(tests) - 1):
                 fmt += ','
-            print(fmt %(filename_str ,TMax, TAvg, MMax, MAvg, SMax, MAvg))
+            print((fmt %(filename_str ,TMax, TAvg, MMax, MAvg, SMax, MAvg)))
     except KeyboardInterrupt:
         print('fail')
 
     return dict((filename, dict(TMax=TMax, TAvg=TAvg, MMax=MMax, MAvg=MAvg, SMax=SMax, SAvg=SAvg))
-            for filename, (TMax, TAvg, MMax, MAvg, SMax, SAvg) in bench_map.iteritems())
+            for filename, (TMax, TAvg, MMax, MAvg, SMax, SAvg) in bench_map.items())
 
 def compare(current, baseline):
     percent_speedups = []
-    for key, current_result in current.iteritems():
+    for key, current_result in current.items():
         try:
             baseline_result = baseline[key]
         except KeyError:
-            print key, 'missing from baseline'
+            print(key, 'missing from baseline')
             continue
 
         val_getter = itemgetter('TMax', 'TAvg', 'MMax', 'MAvg', 'SMax', 'SAvg')
@@ -113,9 +114,9 @@ def compare(current, baseline):
             result = 'SLOWER: %6.2f > baseline %6.2f (%+6.2f%%) ' % \
                     (CTAvg, BTAvg, slowdown)
             percent_speedups.append(slowdown)
-        print '%30s: %s' % (key, result)
+        print('%30s: %s' % (key, result))
     if percent_speedups:
-        print 'Average speedup: %.2f%%' % avg(percent_speedups)
+        print('Average speedup: %.2f%%' % avg(percent_speedups))
 
 if __name__ == '__main__':
     script_path = os.path.abspath(__file__)
@@ -141,7 +142,7 @@ if __name__ == '__main__':
     test_list = find_tests(test_dir)
 
     if not test_list:
-        print >> sys.stderr, "No tests found matching command line arguments."
+        print("No tests found matching command line arguments.", file=sys.stderr)
         sys.exit(0)
 
     test_list = [ Test.from_file(tst, name, OPTIONS) for tst, name in test_list ]
@@ -153,7 +154,7 @@ if __name__ == '__main__':
 
     except OSError:
         if not os.path.exists(JS):
-            print >> sys.stderr, "JS shell argument: file does not exist: '%s'"%JS
+            print("JS shell argument: file does not exist: '%s'"%JS, file=sys.stderr)
             sys.exit(1)
         else:
             raise
diff --git a/js/src/devtools/rootAnalysis/analyze.py b/js/src/devtools/rootAnalysis/analyze.py
index 69482dab7b..610d41f192 100755
--- a/js/src/devtools/rootAnalysis/analyze.py
+++ b/js/src/devtools/rootAnalysis/analyze.py
@@ -9,6 +9,7 @@
 Runs the static rooting analysis
 """
 
+from __future__ import print_function
 from subprocess import Popen
 import subprocess
 import os
@@ -61,7 +62,7 @@ def print_command(command, outfile=None, env=None):
                     outputs.append("%s='%s'" % (key, value))
             output = ' '.join(outputs) + " " + output
 
-    print output
+    print(output)
 
 def generate_hazards(config, outfilename):
     jobs = []
@@ -150,13 +151,13 @@ def out_indexes(command):
 
 def run_job(name, config):
     cmdspec, outfiles = JOBS[name]
-    print("Running " + name + " to generate " + str(outfiles))
+    print(("Running " + name + " to generate " + str(outfiles)))
     if hasattr(cmdspec, '__call__'):
         cmdspec(config, outfiles)
     else:
         temp_map = {}
         cmdspec = fill(cmdspec, config)
-        if isinstance(outfiles, basestring):
+        if isinstance(outfiles, str):
             stdout_filename = '%s.tmp' % name
             temp_map[stdout_filename] = outfiles
             if config['verbose']:
@@ -188,7 +189,7 @@ def run_job(name, config):
             try:
                 os.rename(temp, final)
             except OSError:
-                print("Error renaming %s -> %s" % (temp, final))
+                print(("Error renaming %s -> %s" % (temp, final)))
                 raise
 
 config = { 'ANALYSIS_SCRIPTDIR': os.path.dirname(__file__) }
@@ -224,9 +225,9 @@ args = parser.parse_args()
 
 for default in defaults:
     try:
-        execfile(default, config)
+        exec(compile(open(default, "rb").read(), default, 'exec'), config)
         if args.verbose:
-            print("Loaded %s" % default)
+            print(("Loaded %s" % default))
     except:
         pass
 
@@ -272,14 +273,14 @@ if args.list:
     for step in steps:
         command, outfilename = JOBS[step]
         if outfilename:
-            print("%s -> %s" % (step, outfilename))
+            print(("%s -> %s" % (step, outfilename)))
         else:
             print(step)
     sys.exit(0)
 
 for step in steps:
     command, outfiles = JOBS[step]
-    if isinstance(outfiles, basestring):
+    if isinstance(outfiles, str):
         data[step] = outfiles
     else:
         outfile = 0
diff --git a/js/src/devtools/rootAnalysis/explain.py b/js/src/devtools/rootAnalysis/explain.py
index dc8b76f5c6..54bcee53a2 100755
--- a/js/src/devtools/rootAnalysis/explain.py
+++ b/js/src/devtools/rootAnalysis/explain.py
@@ -1,5 +1,6 @@
 #!/usr/bin/python
 
+from __future__ import print_function
 import re
 import argparse
 
@@ -34,20 +35,20 @@ try:
             m = re.match(r'^Time: (.*)', line)
             mm = re.match(r'^Run on:', line)
             if m or mm:
-                print >>hazards, line
-                print >>extra, line
-                print >>refs, line
+                print(line, file=hazards)
+                print(line, file=extra)
+                print(line, file=refs)
                 continue
 
             m = re.match(r'^Function.*has unnecessary root', line)
             if m:
-                print >>extra, line
+                print(line, file=extra)
                 continue
 
             m = re.match(r'^Function.*takes unsafe address of unrooted', line)
             if m:
                 num_refs += 1
-                print >>refs, line
+                print(line, file=refs)
                 continue
 
             m = re.match(r"^Function.*has unrooted.*of type.*live across GC call ('?)(.*?)('?) at \S+:\d+$", line)
@@ -90,14 +91,14 @@ try:
             gcHazards = hazardousGCFunctions[gcFunction]
 
             if gcFunction in gcExplanations:
-                print >>hazards, (gcHazards[index] + gcExplanations[gcFunction])
+                print((gcHazards[index] + gcExplanations[gcFunction]), file=hazards)
             else:
-                print >>hazards, gcHazards[index]
+                print(gcHazards[index], file=hazards)
 
 except IOError as e:
-    print 'Failed: %s' % str(e)
+    print('Failed: %s' % str(e))
 
-print("Wrote %s" % args.hazards)
-print("Wrote %s" % args.extra)
-print("Wrote %s" % args.refs)
-print("Found %d hazards and %d unsafe references" % (num_hazards, num_refs))
+print(("Wrote %s" % args.hazards))
+print(("Wrote %s" % args.extra))
+print(("Wrote %s" % args.refs))
+print(("Found %d hazards and %d unsafe references" % (num_hazards, num_refs)))
diff --git a/js/src/devtools/rootAnalysis/run-test.py b/js/src/devtools/rootAnalysis/run-test.py
index 3bc9085a0a..fca7dedeeb 100644
--- a/js/src/devtools/rootAnalysis/run-test.py
+++ b/js/src/devtools/rootAnalysis/run-test.py
@@ -3,6 +3,7 @@
 # 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 print_function
 import os
 import site
 import subprocess
@@ -85,5 +86,5 @@ for name in cfg.tests:
 
     os.chdir(outdir)
     subprocess.call(["sh", "-c", "rm *.xdb"])
-    execfile(os.path.join(indir, "test.py"), {'test': test, 'equal': equal})
-    print("TEST-PASSED: %s" % name)
+    exec(compile(open(os.path.join(indir, "test.py"), "rb").read(), os.path.join(indir, "test.py"), 'exec'), {'test': test, 'equal': equal})
+    print(("TEST-PASSED: %s" % name))
diff --git a/js/src/devtools/rootAnalysis/t/hazards/test.py b/js/src/devtools/rootAnalysis/t/hazards/test.py
index 3eb08aa09d..75c7bf720e 100644
--- a/js/src/devtools/rootAnalysis/t/hazards/test.py
+++ b/js/src/devtools/rootAnalysis/t/hazards/test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 test.compile("source.cpp")
 test.run_analysis_script('gcTypes')
 
@@ -22,7 +23,7 @@ assert('<returnvalue>' in hazmap)
 
 # All hazards should be in f() and loopy()
 assert(hazmap['cell2'].function == 'Cell* f()')
-print(len(set(haz.function for haz in hazards)))
+print((len(set(haz.function for haz in hazards))))
 assert(len(set(haz.function for haz in hazards)) == 2)
 
 # Check that the correct GC call is reported for each hazard. (cell3 has a
diff --git a/js/src/devtools/rootAnalysis/t/suppression/test.py b/js/src/devtools/rootAnalysis/t/suppression/test.py
index 65974cc336..ad33411460 100644
--- a/js/src/devtools/rootAnalysis/t/suppression/test.py
+++ b/js/src/devtools/rootAnalysis/t/suppression/test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 test.compile("source.cpp")
 test.run_analysis_script('gcTypes', upto='gcFunctions')
 
@@ -9,9 +10,9 @@ suppressed = test.load_suppressed_functions()
 
 # Only one of these is fully suppressed (ie, *always* called within the scope
 # of an AutoSuppressGC).
-assert(len(filter(lambda f: 'suppressedFunction' in f, suppressed)) == 1)
-assert(len(filter(lambda f: 'halfSuppressedFunction' in f, suppressed)) == 0)
-assert(len(filter(lambda f: 'unsuppressedFunction' in f, suppressed)) == 0)
+assert(len([f for f in suppressed if 'suppressedFunction' in f]) == 1)
+assert(len([f for f in suppressed if 'halfSuppressedFunction' in f]) == 0)
+assert(len([f for f in suppressed if 'unsuppressedFunction' in f]) == 0)
 
 # gcFunctions should be the inverse, but we get to rely on unmangled names here.
 gcFunctions = test.load_gcFunctions()
diff --git a/js/src/devtools/rootAnalysis/t/testlib.py b/js/src/devtools/rootAnalysis/t/testlib.py
index 438398f1ed..27d34d12f3 100644
--- a/js/src/devtools/rootAnalysis/t/testlib.py
+++ b/js/src/devtools/rootAnalysis/t/testlib.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import json
 import os
 import re
@@ -13,7 +14,7 @@ HazardSummary = namedtuple('HazardSummary', ['function', 'variable', 'type', 'GC
 
 def equal(got, expected):
     if got != expected:
-        print("Got '%s', expected '%s'" % (got, expected))
+        print(("Got '%s', expected '%s'" % (got, expected)))
 
 def extract_unmangled(func):
     return func.split('$')[-1]
@@ -37,16 +38,16 @@ class Test(object):
             CXX=self.cfg.cxx, sixgill=self.cfg.sixgill_plugin,
             options=options)
         if self.cfg.verbose:
-            print("Running %s" % cmd)
+            print(("Running %s" % cmd))
         subprocess.check_call(["sh", "-c", cmd])
 
     def load_db_entry(self, dbname, pattern):
         '''Look up an entry from an XDB database file, 'pattern' may be an exact
         matching string, or an re pattern object matching a single entry.'''
 
-        if not isinstance(pattern, basestring):
+        if not isinstance(pattern, str):
             output = subprocess.check_output([self.binpath("xdbkeys"), dbname + ".xdb"])
-            matches = filter(lambda _: re.search(pattern, _), output.splitlines())
+            matches = [_ for _ in output.splitlines() if re.search(pattern, _)]
             if len(matches) == 0:
                 raise Exception("entry not found")
             if len(matches) > 1:
@@ -57,7 +58,7 @@ class Test(object):
         return json.loads(output)
 
     def run_analysis_script(self, phase, upto=None):
-        file("defaults.py", "w").write('''\
+        open("defaults.py", "w").write('''\
 analysis_scriptdir = '{scriptdir}'
 sixgill_bin = '{bindir}'
 '''.format(scriptdir=scriptdir, bindir=self.cfg.sixgill_bin))
@@ -69,7 +70,7 @@ sixgill_bin = '{bindir}'
         cmd.append("--js=%s" % self.cfg.js)
         if self.cfg.verbose:
             cmd.append("--verbose")
-            print("Running " + " ".join(cmd))
+            print(("Running " + " ".join(cmd)))
         subprocess.check_call(cmd)
 
     def computeGCTypes(self):
@@ -80,8 +81,8 @@ sixgill_bin = '{bindir}'
 
     def load_text_file(self, filename, extract=lambda l: l):
         fullpath = os.path.join(self.outdir, filename)
-        values = (extract(line.strip()) for line in file(fullpath))
-        return filter(lambda _: _ is not None, values)
+        values = (extract(line.strip()) for line in open(fullpath))
+        return [_ for _ in values if _ is not None]
 
     def load_suppressed_functions(self):
         return set(self.load_text_file("suppressedFunctions.lst"))
diff --git a/js/src/frontend/GenerateReservedWords.py b/js/src/frontend/GenerateReservedWords.py
index bd698cc5f0..8095a9d4df 100644
--- a/js/src/frontend/GenerateReservedWords.py
+++ b/js/src/frontend/GenerateReservedWords.py
@@ -80,14 +80,14 @@ def split_list_per_column(reserved_word_list, column):
         per_column = column_dict.setdefault(word[column], [])
         per_column.append(item)
 
-    return sorted(column_dict.items(), key=lambda (char, word): ord(char))
+    return sorted(list(column_dict.items()), key=lambda char_word: ord(char_word[0]))
 
 def generate_letter_switch(opt, unprocessed_columns, reserved_word_list,
                            columns=None):
     assert(len(reserved_word_list) != 0);
 
     if not columns:
-        columns = range(0, unprocessed_columns)
+        columns = list(range(0, unprocessed_columns))
 
     if len(reserved_word_list) == 1:
         index, word = reserved_word_list[0]
@@ -161,7 +161,7 @@ def split_list_per_length(reserved_word_list):
         per_length = length_dict.setdefault(len(word), [])
         per_length.append(item)
 
-    return sorted(length_dict.items(), key=lambda (length, word): length)
+    return sorted(list(length_dict.items()), key=lambda length_word: length_word[0])
 
 def generate_switch(opt, reserved_word_list):
     assert(len(reserved_word_list) != 0);
diff --git a/js/src/gdb/mozilla/ExecutableAllocator.py b/js/src/gdb/mozilla/ExecutableAllocator.py
index e1ff812403..4ebe31a49b 100644
--- a/js/src/gdb/mozilla/ExecutableAllocator.py
+++ b/js/src/gdb/mozilla/ExecutableAllocator.py
@@ -62,7 +62,7 @@ class jsjitExecutableAllocator(object):
             self.index = self.index + 1
             if self.table[cur]['keyHash'] > 1: # table[i]->isLive()
                 return self.table[cur]['mem']['u']['mDummy'].cast(self.entryType)
-            return self.next()
+            return next(self)
 
 @ptr_pretty_printer("js::jit::ExecutablePool")
 class jsjitExecutablePool(mozilla.prettyprinters.Pointer):
diff --git a/js/src/gdb/mozilla/JSString.py b/js/src/gdb/mozilla/JSString.py
index 99d5ce987d..7c60d8e2ac 100644
--- a/js/src/gdb/mozilla/JSString.py
+++ b/js/src/gdb/mozilla/JSString.py
@@ -3,6 +3,7 @@
 import gdb
 import mozilla.prettyprinters
 from mozilla.prettyprinters import pretty_printer, ptr_pretty_printer
+unichr = chr
 
 try:
     chr(10000) # UPPER RIGHT PENCIL
diff --git a/js/src/gdb/mozilla/asmjs.py b/js/src/gdb/mozilla/asmjs.py
index 43fac20c73..c6d742abd9 100644
--- a/js/src/gdb/mozilla/asmjs.py
+++ b/js/src/gdb/mozilla/asmjs.py
@@ -3,6 +3,7 @@ In asm code, out-of-bounds heap accesses cause segfaults, which the engine
 handles internally. Make GDB ignore them.
 """
 
+from __future__ import print_function
 import gdb
 
 SIGSEGV = 11
diff --git a/js/src/gdb/mozilla/autoload.py b/js/src/gdb/mozilla/autoload.py
index 43cbcdf721..0acb2dd484 100644
--- a/js/src/gdb/mozilla/autoload.py
+++ b/js/src/gdb/mozilla/autoload.py
@@ -1,5 +1,6 @@
 # mozilla/autoload.py: Autoload SpiderMonkey pretty-printers.
 
+from __future__ import print_function
 print("Loading JavaScript value pretty-printers; see js/src/gdb/README.")
 print("If they cause trouble, type: disable pretty-printer .* SpiderMonkey")
 
diff --git a/js/src/gdb/mozilla/unwind.py b/js/src/gdb/mozilla/unwind.py
index adea63ea6c..73036a4d6f 100644
--- a/js/src/gdb/mozilla/unwind.py
+++ b/js/src/gdb/mozilla/unwind.py
@@ -10,14 +10,14 @@ from mozilla.ExecutableAllocator import jsjitExecutableAllocatorCache, jsjitExec
 # For ease of use in Python 2, we use "long" instead of "int"
 # everywhere.
 try:
-    long
+    int
 except NameError:
     long = int
 
 # The Python 3 |map| built-in works lazily, but in Python 2 we need
 # itertools.imap to get this.
 try:
-    from itertools import imap
+    
 except ImportError:
     imap = map
 
@@ -66,7 +66,7 @@ class UnwinderTypeCache(object):
         return self.d[name]
 
     def value(self, name):
-        return long(gdb.parse_and_eval('js::jit::' + name))
+        return int(gdb.parse_and_eval('js::jit::' + name))
 
     def initialize(self):
         self.d = {}
@@ -94,7 +94,7 @@ class UnwinderTypeCache(object):
         self.d['JSScript'] = gdb.lookup_type("JSScript").pointer()
         self.d['Value'] = gdb.lookup_type("JS::Value")
 
-        self.d['SOURCE_SLOT'] = long(gdb.parse_and_eval('js::ScriptSourceObject::SOURCE_SLOT'))
+        self.d['SOURCE_SLOT'] = int(gdb.parse_and_eval('js::ScriptSourceObject::SOURCE_SLOT'))
         self.d['NativeObject'] = gdb.lookup_type("js::NativeObject").pointer()
         self.d['HeapSlot'] = gdb.lookup_type("js::HeapSlot").pointer()
         self.d['ScriptSource'] = gdb.lookup_type("js::ScriptSource").pointer()
@@ -105,7 +105,7 @@ class UnwinderTypeCache(object):
         for field in t.fields():
             # Strip off "js::jit::".
             name = field.name[9:]
-            enumval = long(field.enumval)
+            enumval = int(field.enumval)
             self.d[name] = enumval
             self.frame_enum_names[enumval] = name
             class_type = gdb.lookup_type('js::jit::' + SizeOfFramePrefix[name])
@@ -134,7 +134,7 @@ def parse_proc_maps():
             if name is '' or (name.startswith('[') and name is not '[vdso]'):
                 # Skip entries not corresponding to a file.
                 continue
-            mappings.append((long(start, 16), long(end, 16)))
+            mappings.append((int(start, 16), int(end, 16)))
     return mappings
 
 # A symbol/value pair as expected from gdb frame decorators.
@@ -159,7 +159,7 @@ class JitFrameDecorator(FrameDecorator):
         self.cache = cache
 
     def _decode_jitframe(self, this_frame):
-        calleetoken = long(this_frame['calleeToken_'])
+        calleetoken = int(this_frame['calleeToken_'])
         tag = calleetoken & 3
         calleetoken = calleetoken ^ tag
         function = None
@@ -224,7 +224,7 @@ class JitFrameDecorator(FrameDecorator):
             return FrameDecorator.frame_args(self)
         # Construct and return an iterable of all the arguments.
         result = []
-        num_args = long(this_frame["numActualArgs_"])
+        num_args = int(this_frame["numActualArgs_"])
         # Sometimes we see very large values here, so truncate it to
         # bypass the damage.
         if num_args > 10:
@@ -263,7 +263,7 @@ class SpiderMonkeyFrameFilter(object):
         return JitFrameDecorator(frame, info, self.cache)
 
     def filter(self, frame_iter):
-        return imap(self.maybe_wrap_frame, frame_iter)
+        return map(self.maybe_wrap_frame, frame_iter)
 
 # A frame id class, as specified by the gdb unwinder API.
 class SpiderMonkeyFrameId(object):
@@ -306,7 +306,7 @@ class UnwinderState(object):
     # Otherwise, return None.  This is used by the frame filter to
     # display extra information about the frame.
     def get_frame(self, frame):
-        sp = long(frame.read_register(self.SP_REGISTER))
+        sp = int(frame.read_register(self.SP_REGISTER))
         if sp in self.frame_map:
             return self.frame_map[sp]
         return None
@@ -315,7 +315,7 @@ class UnwinderState(object):
     # queried by |self.get_frame|.  |sp| is the frame's stack pointer,
     # and |name| the frame's type as a string, e.g. "JitFrame_Exit".
     def add_frame(self, sp, name = None, this_frame = None):
-        self.frame_map[long(sp)] = { "name": name, "this_frame": this_frame }
+        self.frame_map[int(sp)] = { "name": name, "this_frame": this_frame }
 
     # See whether |pc| is claimed by some text mapping.  See
     # |parse_proc_maps| for details on how the decision is made.
@@ -362,12 +362,12 @@ class UnwinderState(object):
     # the size of this frame's header; and |frame_type| is an integer
     # representing the previous frame's type.
     def unpack_descriptor(self, common):
-        value = long(common['descriptor_'])
+        value = int(common['descriptor_'])
         local_size = value >> self.typecache.FRAMESIZE_SHIFT
         header_size = ((value >> self.typecache.FRAME_HEADER_SIZE_SHIFT) &
                        self.typecache.FRAME_HEADER_SIZE_MASK)
         header_size = header_size * self.typecache.void_starstar.sizeof
-        frame_type = long(value & self.typecache.FRAMETYPE_MASK)
+        frame_type = int(value & self.typecache.FRAMETYPE_MASK)
         if frame_type == self.typecache.JitFrame_Entry:
             # Trampoline-x64.cpp pushes a JitFrameLayout object, but
             # the stack pointer is actually adjusted as if a
@@ -470,7 +470,7 @@ class UnwinderState(object):
 
         # If the jit does not claim this address, bail.  GDB defers to our
         # unwinder by default, but we don't really want that kind of power.
-        if not self.is_jit_address(long(pc)):
+        if not self.is_jit_address(int(pc)):
             return None
 
         if self.next_sp is not None:
diff --git a/js/src/gdb/run-tests.py b/js/src/gdb/run-tests.py
index 1e4f4783b0..b341b9dbc3 100644
--- a/js/src/gdb/run-tests.py
+++ b/js/src/gdb/run-tests.py
@@ -5,6 +5,7 @@
 
 # run-tests.py -- Python harness for GDB SpiderMonkey support
 
+from __future__ import print_function
 import os, re, subprocess, sys, traceback
 from threading import Thread
 
@@ -104,7 +105,7 @@ class Summary(object):
 
         if self.failures:
 
-            print "tests failed:"
+            print("tests failed:")
             for test in self.failures:
                 test.show(sys.stdout)
 
@@ -129,7 +130,7 @@ class Summary(object):
                     sys.exit(1)
 
         if self.timeouts:
-            print "tests timed out:"
+            print("tests timed out:")
             for test in self.timeouts:
                 test.show(sys.stdout)
 
@@ -187,7 +188,7 @@ class Test(TaskPool.Task):
         self.summary.timeout(self)
 
     def show_cmd(self, out):
-        print "Command: ", make_shell_cmd(self.cmd())
+        print("Command: ", make_shell_cmd(self.cmd()))
 
     def show_output(self, out):
         if self.stdout:
diff --git a/js/src/gdb/taskpool.py b/js/src/gdb/taskpool.py
index 8bfcb3a345..7632c99937 100644
--- a/js/src/gdb/taskpool.py
+++ b/js/src/gdb/taskpool.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import fcntl, os, select, time
 from subprocess import Popen, PIPE
 
@@ -68,7 +69,7 @@ class TaskPool(object):
     # Set self.next_pending to the next task that has not yet been executed.
     def get_next_pending(self):
         try:
-            return self.pending.next()
+            return next(self.pending)
         except StopIteration:
             return None
 
@@ -203,17 +204,17 @@ if __name__ == '__main__':
             def cmd(self):
                 return ['sh', '-c', 'echo out; sleep %d; echo err>&2' % (self.n,)]
             def onStdout(self, text):
-                print '%d stdout: %r' % (self.n, text)
+                print('%d stdout: %r' % (self.n, text))
             def onStderr(self, text):
-                print '%d stderr: %r' % (self.n, text)
+                print('%d stderr: %r' % (self.n, text))
             def onFinished(self, returncode):
-                print '%d (rc=%d)' % (self.n, returncode)
+                print('%d (rc=%d)' % (self.n, returncode))
                 sorted.append(self.n)
             def onTimeout(self):
-                print '%d timed out' % (self.n,)
+                print('%d timed out' % (self.n,))
 
         p = TaskPool([SortableTask(_) for _ in ns], job_limit=len(ns), timeout=timeout)
         p.run_all()
         return sorted
 
-    print repr(sleep_sort([1,1,2,3,5,8,13,21,34], 15))
+    print(repr(sleep_sort([1,1,2,3,5,8,13,21,34], 15)))
diff --git a/js/src/gdb/tests/test-unwind.py b/js/src/gdb/tests/test-unwind.py
index 6ddf0cd22b..deed741033 100644
--- a/js/src/gdb/tests/test-unwind.py
+++ b/js/src/gdb/tests/test-unwind.py
@@ -1,5 +1,6 @@
 # Test the unwinder and the frame filter.
 
+from __future__ import print_function
 import platform
 
 def do_unwinder_test():
@@ -21,7 +22,7 @@ def do_unwinder_test():
     found_outer = False
     frames = list(gdb.frames.execute_frame_filters(gdb.newest_frame(), 0, -1))
     for frame in frames:
-        print("examining " + frame.function())
+        print(("examining " + frame.function()))
         if first:
             assert_eq(frame.function().startswith("Something"), True)
             first = False
diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py
index 084af2d4e5..9411d037cc 100755
--- a/js/src/jit-test/jit_test.py
+++ b/js/src/jit-test/jit_test.py
@@ -42,7 +42,7 @@ def choose_item(jobs, max_items, display):
     for i, job in enumerate(jobs, 1):
         print("{}) {}".format(i, display(job)))
 
-    item = raw_input('Which one:\n')
+    item = input('Which one:\n')
     try:
         item = int(item)
         if item > job_count or item < 1:
@@ -319,7 +319,7 @@ def main(argv):
             except Exception as e:
                 sys.exit(str(e))
         else:
-            tc = job_list.next()
+            tc = next(job_list)
 
         if options.debugger == 'gdb':
             debug_cmd = ['gdb', '--args']
diff --git a/js/src/jit/arm/gen-double-encoder-table.py b/js/src/jit/arm/gen-double-encoder-table.py
index 1a208fdf40..eb40f40d31 100644
--- a/js/src/jit/arm/gen-double-encoder-table.py
+++ b/js/src/jit/arm/gen-double-encoder-table.py
@@ -10,7 +10,9 @@ modify this file (which is unlikely), you must re-run this script:
 python gen-double-encode-table.py > $(topsrcdir)/path/to/DoubleEntryTable.tbl
 """
 
+from __future__ import print_function
 import operator
+from functools import reduce
 
 def rep(bit, count):
     return reduce(operator.ior, [bit << c for c in range(count)])
@@ -27,6 +29,6 @@ def encodeDouble(value):
     cdefgh = value & 0x3f
     return (a << 31) | (B << 30) | (rep(b, 8) << 22) | cdefgh << 16
 
-print '/* THIS FILE IS AUTOMATICALLY GENERATED BY gen-double-encode-table.py.  */'
+print('/* THIS FILE IS AUTOMATICALLY GENERATED BY gen-double-encode-table.py.  */')
 for i in range(256):
-    print '  { 0x%08x, { %d, %d, 0 } },' % (encodeDouble(i), i & 0xf, i >> 4)
+    print('  { 0x%08x, { %d, %d, 0 } },' % (encodeDouble(i), i & 0xf, i >> 4))
diff --git a/js/src/jsautokw.py b/js/src/jsautokw.py
index fa4b872b52..5cef3d1fe7 100644
--- a/js/src/jsautokw.py
+++ b/js/src/jsautokw.py
@@ -80,14 +80,14 @@ def split_list_per_column(keyword_list, column):
         per_column = column_dict.setdefault(keyword[column], [])
         per_column.append(item)
 
-    return sorted(column_dict.items(), key=lambda (char, keyword): ord(char))
+    return sorted(list(column_dict.items()), key=lambda char_keyword: ord(char_keyword[0]))
 
 def generate_letter_switch(opt, unprocessed_columns, keyword_list,
                            columns=None):
     assert(len(keyword_list) != 0);
 
     if not columns:
-        columns = range(0, unprocessed_columns)
+        columns = list(range(0, unprocessed_columns))
 
     if len(keyword_list) == 1:
         index, keyword = keyword_list[0]
@@ -161,7 +161,7 @@ def split_list_per_length(keyword_list):
         per_length = length_dict.setdefault(len(keyword), [])
         per_length.append(item)
 
-    return sorted(length_dict.items(), key=lambda (length, keyword): length)
+    return sorted(list(length_dict.items()), key=lambda length_keyword: length_keyword[0])
 
 def generate_switch(opt, keyword_list):
     assert(len(keyword_list) != 0);
diff --git a/js/src/tests/compare_bench.py b/js/src/tests/compare_bench.py
index cfe9508cd4..012bd3e0ee 100644
--- a/js/src/tests/compare_bench.py
+++ b/js/src/tests/compare_bench.py
@@ -15,7 +15,7 @@ def avg(seq):
 
 def compare(current, baseline):
     percent_speedups = []
-    for key, current_result in current.iteritems():
+    for key, current_result in current.items():
         try:
             baseline_result = baseline[key]
         except KeyError:
diff --git a/js/src/tests/ecma_6/String/make-normalize-generateddata-input.py b/js/src/tests/ecma_6/String/make-normalize-generateddata-input.py
index c1983dbd18..4373c0e1ae 100644
--- a/js/src/tests/ecma_6/String/make-normalize-generateddata-input.py
+++ b/js/src/tests/ecma_6/String/make-normalize-generateddata-input.py
@@ -12,7 +12,7 @@ import re, sys
 
 sep_pat = re.compile(' +')
 def to_code_list(codes):
-    return '[' + ', '.join(map(lambda x: '0x{0}'.format(x), re.split(sep_pat, codes))) + ']'
+    return '[' + ', '.join(['0x{0}'.format(x) for x in re.split(sep_pat, codes)]) + ']'
 
 def convert(dir):
     ver_pat = re.compile('NormalizationTest-([0-9\.]+)\.txt')
diff --git a/js/src/tests/jstests.py b/js/src/tests/jstests.py
index 6cd92a5e01..26225fd513 100755
--- a/js/src/tests/jstests.py
+++ b/js/src/tests/jstests.py
@@ -170,7 +170,7 @@ def parse_args():
         op.error('missing JS_SHELL argument')
 
     # Valgrind, gdb, and rr are mutually exclusive.
-    if sum(map(lambda e: 1 if e else 0, [options.valgrind, options.debug, options.rr])) > 1:
+    if sum([1 if e else 0 for e in [options.valgrind, options.debug, options.rr]]) > 1:
         op.error("--valgrind, --debug, and --rr are mutually exclusive.")
 
     # Fill the debugger field, as needed.
diff --git a/js/src/tests/lib/jittests.py b/js/src/tests/lib/jittests.py
index 0a1d1537a3..44464fc29e 100755
--- a/js/src/tests/lib/jittests.py
+++ b/js/src/tests/lib/jittests.py
@@ -13,12 +13,12 @@ from collections import namedtuple
 import StringIO
 
 if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
-    from tasks_unix import run_all_tests
+    from .tasks_unix import run_all_tests
 else:
-    from tasks_win import run_all_tests
+    from .tasks_win import run_all_tests
 
-from progressbar import ProgressBar, NullProgressBar
-from results import TestOutput
+from .progressbar import ProgressBar, NullProgressBar
+from .results import TestOutput
 
 TESTS_LIB_DIR = os.path.dirname(os.path.abspath(__file__))
 JS_DIR = os.path.dirname(os.path.dirname(TESTS_LIB_DIR))
@@ -567,7 +567,7 @@ def process_test_results(results, num_tests, pb, options):
                 sys.stdout.write(res.err)
 
             if options.check_output:
-                if res.test.path in output_dict.keys():
+                if res.test.path in list(output_dict.keys()):
                     if output_dict[res.test.path] != res.out:
                         pb.message("FAIL - OUTPUT DIFFERS {}".format(res.test.relpath_tests))
                 else:
@@ -623,7 +623,7 @@ def get_remote_results(tests, device, prefix, options):
     from mozdevice import devicemanager
 
     try:
-        for i in xrange(0, options.repeat):
+        for i in range(0, options.repeat):
             for test in tests:
                 yield run_test_remote(test, device, prefix, options)
     except devicemanager.DMError as e:
diff --git a/js/src/tests/lib/manifest.py b/js/src/tests/lib/manifest.py
index 7079a186f6..f4a18b05ff 100644
--- a/js/src/tests/lib/manifest.py
+++ b/js/src/tests/lib/manifest.py
@@ -7,7 +7,7 @@ from __future__ import print_function
 import os, re, sys
 from subprocess import Popen, PIPE
 
-from tests import RefTestCase
+from .tests import RefTestCase
 
 
 def split_path_into_dirs(path):
@@ -199,7 +199,7 @@ def _emit_manifest_at(location, relative, test_gen, depth):
     filename = os.path.join(location, 'jstests.list')
     manifest = []
     numTestFiles = 0
-    for k, test_list in manifests.iteritems():
+    for k, test_list in manifests.items():
         fullpath = os.path.join(location, k)
         if os.path.isdir(fullpath):
             manifest.append("include " + k + "/jstests.list")
diff --git a/js/src/tests/lib/progressbar.py b/js/src/tests/lib/progressbar.py
index da578783df..bdd7369e90 100644
--- a/js/src/tests/lib/progressbar.py
+++ b/js/src/tests/lib/progressbar.py
@@ -5,9 +5,9 @@ import math
 import sys
 
 if sys.platform.startswith('win'):
-    from terminal_win import Terminal
+    from .terminal_win import Terminal
 else:
-    from terminal_unix import Terminal
+    from .terminal_unix import Terminal
 
 class NullProgressBar(object):
     def update(self, current, data): pass
diff --git a/js/src/tests/lib/results.py b/js/src/tests/lib/results.py
index 451fe5b657..1598789233 100644
--- a/js/src/tests/lib/results.py
+++ b/js/src/tests/lib/results.py
@@ -1,7 +1,7 @@
 from __future__ import print_function
 
 import re
-from progressbar import NullProgressBar, ProgressBar
+from .progressbar import NullProgressBar, ProgressBar
 import pipes
 
 # subprocess.list2cmdline does not properly escape for sh-like shells
@@ -131,7 +131,7 @@ class ResultsSink:
             dev_label = self.LABELS[tup][1]
 
             if self.options.check_output:
-                if output.test.path in self.output_dict.keys():
+                if output.test.path in list(self.output_dict.keys()):
                     if self.output_dict[output.test.path] != output:
                         self.counts['FAIL'] += 1
                         self.print_automation_result(
diff --git a/js/src/tests/lib/tasks_unix.py b/js/src/tests/lib/tasks_unix.py
index 487c749ee2..433e47d4aa 100644
--- a/js/src/tests/lib/tasks_unix.py
+++ b/js/src/tests/lib/tasks_unix.py
@@ -2,10 +2,11 @@
 # waitpid to dispatch tasks.  This avoids several deadlocks that are possible
 # with fork/exec + threads + Python.
 
+from __future__ import print_function
 import errno, os, select, sys
 from datetime import datetime, timedelta
-from progressbar import ProgressBar
-from results import NullTestOutput, TestOutput, escape_cmdline
+from .progressbar import ProgressBar
+from .results import NullTestOutput, TestOutput, escape_cmdline
 
 class Task(object):
     def __init__(self, test, prefix, pid, stdout, stderr):
@@ -25,7 +26,7 @@ def spawn_test(test, prefix, passthrough, run_skipped, show_cmd):
 
     cmd = test.get_command(prefix)
     if show_cmd:
-        print(escape_cmdline(cmd))
+        print((escape_cmdline(cmd)))
 
     if not passthrough:
         (rout, wout) = os.pipe()
@@ -107,7 +108,7 @@ def read_input(tasks, timeout):
     try:
         readable, _, _ = select.select(rlist, [], exlist, timeout)
     except OverflowError as e:
-        print >> sys.stderr, "timeout value", timeout
+        print("timeout value", timeout, file=sys.stderr)
         raise
 
     for fd in readable:
diff --git a/js/src/tests/lib/tasks_win.py b/js/src/tests/lib/tasks_win.py
index a99640abbf..e091775578 100644
--- a/js/src/tests/lib/tasks_win.py
+++ b/js/src/tests/lib/tasks_win.py
@@ -6,10 +6,10 @@ from __future__ import print_function, unicode_literals, division
 import subprocess
 import sys
 from datetime import datetime, timedelta
-from progressbar import ProgressBar
-from results import NullTestOutput, TestOutput, escape_cmdline
+from .progressbar import ProgressBar
+from .results import NullTestOutput, TestOutput, escape_cmdline
 from threading import Thread
-from Queue import Queue, Empty
+from queue import Queue, Empty
 
 
 class EndMarker:
@@ -22,7 +22,7 @@ class TaskFinishedMarker:
 
 def _do_work(qTasks, qResults, qWatch, prefix, run_skipped, timeout, show_cmd):
     while True:
-        test = qTasks.get(block=True, timeout=sys.maxint)
+        test = qTasks.get(block=True, timeout=sys.maxsize)
         if test is EndMarker:
             qWatch.put(EndMarker)
             qResults.put(EndMarker)
@@ -73,7 +73,7 @@ def _do_watch(qWatch, timeout):
                 # ignore this.
                 if ex.winerror != 5:
                     raise
-            fin = qWatch.get(block=True, timeout=sys.maxint)
+            fin = qWatch.get(block=True, timeout=sys.maxsize)
             assert fin is TaskFinishedMarker, "invalid finish marker"
 
 
diff --git a/js/src/tests/lib/tests.py b/js/src/tests/lib/tests.py
index 1de56dc1c4..af31f9a7eb 100644
--- a/js/src/tests/lib/tests.py
+++ b/js/src/tests/lib/tests.py
@@ -3,12 +3,13 @@
 # This contains classes that represent an individual test, including
 # metadata, and know how to run the tests and determine failures.
 
+from __future__ import print_function
 import datetime, os, sys, time
 from contextlib import contextmanager
 from subprocess import Popen, PIPE
 from threading import Thread
 
-from results import TestOutput
+from .results import TestOutput
 
 # When run on tbpl, we run each test multiple times with the following
 # arguments.
@@ -43,14 +44,14 @@ JITFLAGS = {
 
 def get_jitflags(variant, **kwargs):
     if variant not in JITFLAGS:
-        print('Invalid jitflag: "{}"'.format(variant))
+        print(('Invalid jitflag: "{}"'.format(variant)))
         sys.exit(1)
     if variant == 'none' and 'none' in kwargs:
         return kwargs['none']
     return JITFLAGS[variant]
 
 def valid_jitflags():
-    return JITFLAGS.keys()
+    return list(JITFLAGS.keys())
 
 def get_environment_overlay(js_shell):
     """
diff --git a/js/src/tests/parsemark.py b/js/src/tests/parsemark.py
index 5c2fa4a71f..13420fba97 100644
--- a/js/src/tests/parsemark.py
+++ b/js/src/tests/parsemark.py
@@ -96,7 +96,7 @@ def parsemark(filepaths, fbench, stfu=False):
             print('Parsemarking {}...'.format(filename))
         bench_map[filename] = fbench(filepath)
     print('{')
-    for i, (filename, (avg, stddev)) in enumerate(bench_map.iteritems()):
+    for i, (filename, (avg, stddev)) in enumerate(bench_map.items()):
         assert '"' not in filename
         fmt = '    {:30s}: {{"average_ms": {:6.2f}, "stddev_ms": {:6.2f}}}'
         if i != len(bench_map) - 1:
@@ -105,7 +105,7 @@ def parsemark(filepaths, fbench, stfu=False):
         print(fmt.format(filename_str, avg, stddev))
     print('}')
     return dict((filename, dict(average_ms=avg, stddev_ms=stddev))
-                for filename, (avg, stddev) in bench_map.iteritems())
+                for filename, (avg, stddev) in bench_map.items())
 
 
 def main():
diff --git a/js/src/vm/make_opcode_doc.py b/js/src/vm/make_opcode_doc.py
index 454d8b8d5e..b30e8ce6f6 100755
--- a/js/src/vm/make_opcode_doc.py
+++ b/js/src/vm/make_opcode_doc.py
@@ -275,20 +275,18 @@ def print_opcode(opcode):
     names_template = '{name} [-{nuses}, +{ndefs}]{flags}'
     opcodes = sorted([opcode] + opcode.group,
                      key=lambda opcode: opcode.name)
-    names = map(lambda code: names_template.format(name=escape(code.name),
+    names = [names_template.format(name=escape(code.name),
                                                    nuses=override(code.nuses,
                                                                   opcode.nuses_override),
                                                    ndefs=override(code.ndefs,
                                                                   opcode.ndefs_override),
-                                                   flags=format_flags(code.flags)),
-                opcodes)
+                                                   flags=format_flags(code.flags)) for code in opcodes]
     if len(opcodes) == 1:
         values = ['{value} (0x{value:02x})'.format(value=opcode.value)]
     else:
         values_template = '{name}: {value} (0x{value:02x})'
-        values = map(lambda code: values_template.format(name=escape(code.name),
-                                                         value=code.value),
-                    opcodes)
+        values = [values_template.format(name=escape(code.name),
+                                                         value=code.value) for code in opcodes]
 
     print("""<dt id="{id}">{names}</dt>
 <dd>
diff --git a/js/src/vm/make_unicode.py b/js/src/vm/make_unicode.py
index 8568ccb64c..9f96543a4c 100755
--- a/js/src/vm/make_unicode.py
+++ b/js/src/vm/make_unicode.py
@@ -27,8 +27,10 @@ import os
 import sys
 from contextlib import closing
 from functools import partial
-from itertools import chain, groupby, ifilter, imap, izip_longest, tee
+from itertools import chain, groupby, tee
 from operator import is_not, itemgetter
+import six
+from itertools import zip_longest
 
 class codepoint_dict(dict):
     def name(self, code_point):
@@ -103,12 +105,12 @@ def read_unicode_data(unicode_data):
     reader = csv.reader(unicode_data, delimiter=';')
 
     while True:
-        row = reader.next()
+        row = next(reader)
         name = row[1]
 
         # We need to expand the UAX #44 4.2.3 Code Point Range
         if name.startswith('<') and name.endswith('First>'):
-            next_row = reader.next()
+            next_row = next(reader)
 
             for i in range(int(row[0], 16), int(next_row[0], 16) + 1):
                 row[0] = i
@@ -172,7 +174,7 @@ def int_ranges(ints):
     """ Yields consecutive ranges (inclusive) from integer values. """
     (a, b) = tee(sorted(ints))
     start = next(b)
-    for (curr, succ) in izip_longest(a, b):
+    for (curr, succ) in zip_longest(a, b):
         if curr + 1 != succ:
             yield (start, curr)
             start = succ
@@ -527,16 +529,16 @@ def process_special_casing(special_casing, table, index):
         return upper
 
     def ascii(char_dict):
-        return ifilter(lambda ch: ch <= 0x7f, char_dict.iterkeys())
+        return filter(lambda ch: ch <= 0x7f, char_dict.keys())
 
     def latin1(char_dict):
-        return ifilter(lambda ch: ch <= 0xff, char_dict.iterkeys())
+        return filter(lambda ch: ch <= 0xff, char_dict.keys())
 
     def is_empty(iterable):
         return not any(True for _ in iterable)
 
     def is_equals(iter1, iter2):
-        return all(x == y for (x, y) in izip_longest(iter1, iter2))
+        return all(x == y for (x, y) in zip_longest(iter1, iter2))
 
     # Ensure no ASCII characters have special case mappings.
     assert is_empty(ascii(unconditional_tolower))
@@ -567,28 +569,28 @@ def process_special_casing(special_casing, table, index):
     assert all(ch != lowerCase(ch) for ch in [0x0130, 0x03A3])
 
     # Ensure Azeri, Lithuanian, and Turkish are the only languages with conditional case mappings.
-    assert is_equals(["az", "lt", "tr"], sorted(lang_conditional_tolower.iterkeys()))
-    assert is_equals(["az", "lt", "tr"], sorted(lang_conditional_toupper.iterkeys()))
+    assert is_equals(["az", "lt", "tr"], sorted(lang_conditional_tolower.keys()))
+    assert is_equals(["az", "lt", "tr"], sorted(lang_conditional_toupper.keys()))
 
     # Maximum case mapping length is three characters.
-    itervals = lambda d: d.itervalues()
-    assert max(imap(len, chain(
+    itervals = lambda d: d.values()
+    assert max(map(len, chain(
         itervals(unconditional_tolower),
         itervals(unconditional_toupper),
-        imap(itemgetter(0), itervals(conditional_tolower)),
-        imap(itemgetter(0), itervals(conditional_toupper)),
-        imap(itemgetter(0), chain.from_iterable(imap(itervals, itervals(lang_conditional_tolower)))),
-        imap(itemgetter(0), chain.from_iterable(imap(itervals, itervals(lang_conditional_toupper)))),
+        map(itemgetter(0), itervals(conditional_tolower)),
+        map(itemgetter(0), itervals(conditional_toupper)),
+        map(itemgetter(0), chain.from_iterable(map(itervals, itervals(lang_conditional_tolower)))),
+        map(itemgetter(0), chain.from_iterable(map(itervals, itervals(lang_conditional_toupper)))),
     ))) <= 3
 
     # Ensure all case mapping contexts are known (see Unicode 9.0, §3.13 Default Case Algorithms).
     assert set([
         'After_I', 'After_Soft_Dotted', 'Final_Sigma', 'More_Above', 'Not_Before_Dot',
-    ]).issuperset(set(ifilter(partial(is_not, None), chain(
-        imap(itemgetter(1), itervals(conditional_tolower)),
-        imap(itemgetter(1), itervals(conditional_toupper)),
-        imap(itemgetter(1), chain.from_iterable(imap(itervals, itervals(lang_conditional_tolower)))),
-        imap(itemgetter(1), chain.from_iterable(imap(itervals, itervals(lang_conditional_toupper)))),
+    ]).issuperset(set(filter(partial(is_not, None), chain(
+        map(itemgetter(1), itervals(conditional_tolower)),
+        map(itemgetter(1), itervals(conditional_toupper)),
+        map(itemgetter(1), chain.from_iterable(map(itervals, itervals(lang_conditional_tolower)))),
+        map(itemgetter(1), chain.from_iterable(map(itervals, itervals(lang_conditional_toupper)))),
     ))))
 
     # Special casing for U+00DF (LATIN SMALL LETTER SHARP S).
@@ -677,7 +679,7 @@ def write_special_casing_methods(unconditional_toupper, codepoint_table, println
                 lines[-1].append(expr)
             else:
                 lines.append([expr])
-        return ' ||\n{}'.format(spaces).join(imap(lambda t: ' || '.join(t), lines))
+        return ' ||\n{}'.format(spaces).join(map(lambda t: ' || '.join(t), lines))
 
     def write_range_accept(parent_list, child_list, depth):
         """ Accepts the input character if it matches any code unit in |child_list|. """
@@ -732,7 +734,7 @@ def write_special_casing_methods(unconditional_toupper, codepoint_table, println
         assert unconditional_toupper, "|unconditional_toupper| is not empty"
 
         # Sorted list of code units with special upper case mappings.
-        code_list = sorted(unconditional_toupper.iterkeys())
+        code_list = sorted(unconditional_toupper.keys())
 
         # Fail-fast if the input character isn't a special casing character.
         println('    if ({})'.format(out_range(code_list[0], code_list[-1])))
@@ -787,7 +789,7 @@ def write_special_casing_methods(unconditional_toupper, codepoint_table, println
         println('{')
 
         println('    switch(ch) {')
-        for (code, converted) in sorted(unconditional_toupper.iteritems(), key=itemgetter(0)):
+        for (code, converted) in sorted(unconditional_toupper.items(), key=itemgetter(0)):
             println('      case {}: return {}; // {}'.format(hexlit(code), len(converted),
                                                              codepoint_table.name(code)))
         println('    }')
@@ -804,7 +806,7 @@ def write_special_casing_methods(unconditional_toupper, codepoint_table, println
         println('{')
 
         println('    switch(ch) {')
-        for (code, converted) in sorted(unconditional_toupper.iteritems(), key=itemgetter(0)):
+        for (code, converted) in sorted(unconditional_toupper.items(), key=itemgetter(0)):
             println('      case {}: // {}'.format(hexlit(code), codepoint_table.name(code)))
             for ch in converted:
                 println('        elements[(*index)++] = {}; // {}'.format(hexlit(ch),
@@ -843,8 +845,8 @@ def make_bmp_mapping_test(version, codepoint_table, unconditional_tolower, uncon
                 (upper, lower, _, _) = entry
                 upper = unconditional_toupper[code] if code in unconditional_toupper else [upper]
                 lower = unconditional_tolower[code] if code in unconditional_tolower else [lower]
-                println('  ["{}", "{}"], /* {} */'.format("".join(imap(unicodeEsc, upper)),
-                                                          "".join(imap(unicodeEsc, lower)),
+                println('  ["{}", "{}"], /* {} */'.format("".join(map(unicodeEsc, upper)),
+                                                          "".join(map(unicodeEsc, lower)),
                                                           codepoint_table.name(code)))
             else:
                 println('  ["{0}", "{0}"],'.format(unicodeEsc(code)))
@@ -1072,7 +1074,7 @@ def make_unicode_file(version,
         println('bool')
         println('js::unicode::{}(uint32_t codePoint)'.format(name))
         println('{')
-        for (from_code, to_code) in int_ranges(group_set.keys()):
+        for (from_code, to_code) in int_ranges(list(group_set.keys())):
             println('    if (codePoint >= 0x{:X} && codePoint <= 0x{:X}) // {} .. {}'.format(from_code,
                                                                                              to_code,
                                                                                              codepoint_table.name(from_code),
@@ -1117,7 +1119,7 @@ def make_unicode_file(version,
         # If the following assert fails, it means space character is added to
         # non-BMP area.  In that case the following code should be uncommented
         # and the corresponding code should be added to frontend.
-        assert len(non_bmp_space_set.keys()) == 0
+        assert len(list(non_bmp_space_set.keys())) == 0
 
         write_supplemental_identifier_method('IsIdentifierStartNonBMP', non_bmp_id_start_set,
                                              println)
@@ -1277,20 +1279,20 @@ def make_irregexp_tables(version,
         # Latin1 characters which, when case-mapped through
         # String.prototype.toUpperCase(), canonicalize to a non-Latin1 character.
         # ES2017, §21.2.2.8.2 Runtime Semantics: Canonicalize
-        casemapped_to_nonlatin1 = ifilter(casemaps_to_nonlatin1, xrange(0, MAX_LATIN1 + 1))
+        casemapped_to_nonlatin1 = filter(casemaps_to_nonlatin1, range(0, MAX_LATIN1 + 1))
 
         def casemap_closure(ch):
             upper = to_upper(ch)
-            return (ch, [c for c in xrange(MAX_LATIN1 + 1, MAX_BMP + 1) if upper == to_upper(c)])
+            return (ch, [c for c in range(MAX_LATIN1 + 1, MAX_BMP + 1) if upper == to_upper(c)])
 
         # Mapping from Latin1 characters to the list of case map equivalent
         # non-Latin1 characters.
-        casemap_for_latin1 = dict(chain(imap(casemap_closure, casemapped_to_nonlatin1)))
+        casemap_for_latin1 = dict(chain(map(casemap_closure, casemapped_to_nonlatin1)))
 
         # Non-latin1 characters which, when Unicode case-folded, canonicalize to
         # a Latin1 character.
         # ES2017, §21.2.2.8.2 Runtime Semantics: Canonicalize
-        casefolded_to_latin1 = ifilter(casefolds_to_latin1, xrange(MAX_LATIN1 + 1, MAX_BMP + 1))
+        casefolded_to_latin1 = filter(casefolds_to_latin1, range(MAX_LATIN1 + 1, MAX_BMP + 1))
 
         println('    if (unicode) {')
         for ch in casefolded_to_latin1:
@@ -1304,11 +1306,11 @@ def make_irregexp_tables(version,
             println('            return {};'.format(consequent(casefolded)))
         println('    }')
         println('')
-        for (ch, casemapped_chars) in casemap_for_latin1.iteritems():
+        for (ch, casemapped_chars) in casemap_for_latin1.items():
             for casemapped in casemapped_chars:
                 println('    // "{}" case maps to "{}".'.format(char_name(casemapped),
                                                                 char_name(ch)))
-            println('    if ({})'.format(' || '.join(imap(test, casemapped_chars))))
+            println('    if ({})'.format(' || '.join(map(test, casemapped_chars))))
             println('        return {};'.format(consequent(ch)))
         println('    return {};'.format(default))
 
@@ -1345,7 +1347,7 @@ def make_irregexp_tables(version,
         character_range = partial(write_character_range, println)
 
         # Characters in \s, 21.2.2.12 CharacterClassEscape.
-        space_chars = filter(is_space, xrange(0, MAX_BMP + 1))
+        space_chars = list(filter(is_space, range(0, MAX_BMP + 1)))
 
         # Characters in \d, 21.2.2.12 CharacterClassEscape.
         digit_chars = map(ord, string.digits)
@@ -1357,10 +1359,10 @@ def make_irregexp_tables(version,
 
         # Characters which case-fold to characters in \w.
         ignorecase_word_chars = (word_chars +
-                                filter(casefolds_to_ascii, xrange(MAX_ASCII + 1, MAX_BMP + 1)))
+                                list(filter(casefolds_to_ascii, range(MAX_ASCII + 1, MAX_BMP + 1))))
 
         # Surrogate characters.
-        surrogate_chars = range(LEAD_SURROGATE_MIN, TRAIL_SURROGATE_MAX + 1)
+        surrogate_chars = list(range(LEAD_SURROGATE_MIN, TRAIL_SURROGATE_MAX + 1))
 
         write(warning_message)
         write(unicode_version_message.format(version))
@@ -1383,7 +1385,7 @@ def make_irregexp_tables(version,
         character_range('IgnoreCaseWord', ignorecase_word_chars)
         character_range('WordAndSurrogate', word_chars + surrogate_chars)
         character_range('NegatedIgnoreCaseWordAndSurrogate',
-                        set(xrange(0, MAX_BMP + 1)) - set(ignorecase_word_chars + surrogate_chars))
+                        set(range(0, MAX_BMP + 1)) - set(ignorecase_word_chars + surrogate_chars))
 
         character_range('Digit', digit_chars)
         character_range('DigitAndSurrogate', digit_chars + surrogate_chars)
@@ -1393,7 +1395,7 @@ def make_irregexp_tables(version,
         character_range('LineTerminator', line_terminator)
 
 def update_unicode(args):
-    import urllib2
+    import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
     version = args.version
     if version is not None:
@@ -1417,7 +1419,7 @@ def update_unicode(args):
         if version is not None:
             print('Downloading %s...' % fname)
             unicode_data_url = '%s/%s' % (url, fname)
-            with closing(urllib2.urlopen(unicode_data_url)) as reader:
+            with closing(six.moves.urllib.request.urlopen(unicode_data_url)) as reader:
                 data = reader.read()
             tfile = io.open(tfile_path, 'w+b')
             tfile.write(data)
diff --git a/layout/generic/frame-graph.py b/layout/generic/frame-graph.py
index ac1076b83c..025ada76d5 100644
--- a/layout/generic/frame-graph.py
+++ b/layout/generic/frame-graph.py
@@ -34,7 +34,7 @@ for line in sys.stdin:
 
 sys.stdout.write('digraph g {\n')
 
-for olist in classdict.itervalues():
+for olist in classdict.values():
     for line in olist:
         sys.stdout.write(line)
 
diff --git a/layout/reftests/border-image/gen-refs.py b/layout/reftests/border-image/gen-refs.py
index 44a89353d1..8850c75ed5 100644
--- a/layout/reftests/border-image/gen-refs.py
+++ b/layout/reftests/border-image/gen-refs.py
@@ -27,6 +27,7 @@
 # Assumes there is no intrinsic size for the border-image-source, so uses
 # the size of the border image area.
 
+from __future__ import print_function
 import sys
 
 class Point:
@@ -65,7 +66,7 @@ class np:
 def parse_p(tok):
   if tok[-2:] == "px":
     return float(tok[:-2])
-  print "Whoops, not a pixel value " + tok
+  print("Whoops, not a pixel value " + tok)
 
 def parse_np(tok):
   if tok[-2:] == "px":
@@ -91,11 +92,11 @@ def parse(filename):
     if toks[0] == "border-image-repeat:":
       props.repeat = toks[1]
     if toks[0] == "border-image-slice:":
-      props.slice = map(parse_p, toks[1:5])
+      props.slice = list(map(parse_p, toks[1:5]))
     if toks[0] == "border-image-width:":
-      props.image_width = map(parse_np, toks[1:5])
+      props.image_width = list(map(parse_np, toks[1:5]))
     if toks[0] == "border-image-outset:":
-      props.outset = map(parse_np, toks[1:5])
+      props.outset = list(map(parse_np, toks[1:5]))
   f.close()
   return props
 
@@ -106,8 +107,8 @@ def normalise(props):
   result = Props()
   result.source = props.source
   result.repeat = props.repeat
-  result.width = map(lambda x: x.get_absolute(props.width), props.image_width)
-  outsets = map(lambda x: x.get_absolute(props.width), props.outset)
+  result.width = [x.get_absolute(props.width) for x in props.image_width]
+  outsets = [x.get_absolute(props.width) for x in props.outset]
   result.size.width = props.size.width + 2*props.width + outsets[1] + outsets[3]
   result.size.height = props.size.height + 2*props.width + outsets[0] + outsets[2]
   result.slice = props.slice
@@ -121,47 +122,47 @@ def normalise(props):
 
 def check_parse(props):
   if not hasattr(props, 'source'):
-    print "missing border-image-source"
+    print("missing border-image-source")
     return False
   if not hasattr(props.size, 'width'):
-    print "missing width"
+    print("missing width")
     return False
   if not hasattr(props.size, 'height'):
-    print "missing height"
+    print("missing height")
     return False
   if not hasattr(props, 'width'):
-    print "missing border-width"
+    print("missing border-width")
     return False
   if not hasattr(props, 'image_width'):
-    print "missing border-image-width"
+    print("missing border-image-width")
     return False
   if not hasattr(props, 'slice'):
-    print "missing border-image-slice"
+    print("missing border-image-slice")
     return False
   if not hasattr(props, 'repeat') or (props.repeat not in ["stretch", "repeat", "round"]):
-    print "missing or incorrect border-image-repeat '" + props.repeat + "'"
+    print("missing or incorrect border-image-repeat '" + props.repeat + "'")
     return False
   if not hasattr(props, 'outset'):
-    print "missing border-image-outset"
+    print("missing border-image-outset")
     return False
 
   return True
 
 def check_normalise(props):
   if not hasattr(props, 'source'):
-    print "missing border-image-source"
+    print("missing border-image-source")
     return False
   if not hasattr(props.size, 'width'):
-    print "missing width"
+    print("missing width")
     return False
   if not hasattr(props.size, 'height'):
-    print "missing height"
+    print("missing height")
     return False
   if not hasattr(props, 'slice'):
-    print "missing border-image-slice"
+    print("missing border-image-slice")
     return False
   if not hasattr(props, 'repeat') or (props.repeat not in ["stretch", "repeat", "round"]):
-    print "missing or incorrect border-image-repeat '" + props.repeat + "'"
+    print("missing or incorrect border-image-repeat '" + props.repeat + "'")
     return False
 
   return True
@@ -180,7 +181,7 @@ class Tile:
 def make_src_tiles():
   tiles = [Tile() for i in range(9)]
 
-  rows = [range(3*i, 3*(i+1)) for i in range(3)]
+  rows = [list(range(3*i, 3*(i+1))) for i in range(3)]
   cols = [[i, i+3, i+6] for i in range(3)]
 
   row_limits_slice = [0, props.slice[3], props.size.width - props.slice[1], props.size.width]
@@ -239,7 +240,7 @@ def compute(props):
     for t in [tiles[i] for i in [3, 4, 5]]:
       t.scale.y = dest_tile_size.height/t.slice.height()
   else:
-    print "Whoops, invalid border-image-repeat value"
+    print("Whoops, invalid border-image-repeat value")
 
   # catch overlapping slices. Its easier to deal with it here than to catch
   # earlier and have to avoid all the divide by zeroes above
@@ -312,34 +313,34 @@ def compute(props):
       dest_tiles[(i+1)*tiles_h-2].dest_size.width -= diff_h
 
   # output the table to simulate the border
-  print "<table>"
+  print("<table>")
   for i in range(tiles_h):
-    print "<col style=\"width: " + str(dest_tiles[i].dest_size.width) + "px;\">"
+    print("<col style=\"width: " + str(dest_tiles[i].dest_size.width) + "px;\">")
   for i in range(tiles_v):
-    print "<tr style=\"height: " + str(dest_tiles[i*tiles_h].dest_size.height) + "px;\">"
+    print("<tr style=\"height: " + str(dest_tiles[i*tiles_h].dest_size.height) + "px;\">")
     for j in range(tiles_h):
       width = dest_tiles[i*tiles_h+j].size.width
       height = dest_tiles[i*tiles_h+j].size.height
       # catch any tiles with negative widths/heights
       # this happends when the total of the border-image-slices > borde drawing area
       if width <= 0 or height <= 0:
-        print "  <td style=\"background: white;\"></td>"
+        print("  <td style=\"background: white;\"></td>")
       else:
-        print "  <td style=\"background-image: " + props.source + "; background-size: " + str(width) + "px " + str(height) + "px; background-position: " + str(dest_tiles[i*tiles_h+j].offset.x) + "px " + str(dest_tiles[i*tiles_h+j].offset.y) + "px;\"></td>"
-    print "</tr>"
-  print "</table>"
+        print("  <td style=\"background-image: " + props.source + "; background-size: " + str(width) + "px " + str(height) + "px; background-position: " + str(dest_tiles[i*tiles_h+j].offset.x) + "px " + str(dest_tiles[i*tiles_h+j].offset.y) + "px;\"></td>")
+    print("</tr>")
+  print("</table>")
 
 
 # start here
 args = sys.argv[1:]
 if len(args) == 0:
-  print "whoops: no source file"
+  print("whoops: no source file")
   exit(1)
 
 
 props = parse(args[0])
 if not check_parse(props):
-  print dir(props)
+  print(dir(props))
   exit(1)
 props = normalise(props)
 if not check_normalise(props):
diff --git a/layout/reftests/fonts/gsubtest/makegsubfonts.py b/layout/reftests/fonts/gsubtest/makegsubfonts.py
index a8aedef0f2..e2e7d5db23 100644
--- a/layout/reftests/fonts/gsubtest/makegsubfonts.py
+++ b/layout/reftests/fonts/gsubtest/makegsubfonts.py
@@ -1,4 +1,5 @@
 
+from __future__ import print_function
 import os
 import textwrap
 from xml.etree import ElementTree
@@ -124,7 +125,7 @@ def makeLookup1():
     		if table.format == 4:
     			table.cmap[cp] = glyphName
     		else:
-    			raise NotImplementedError, "Unsupported cmap table format: %d" % table.format
+    			raise NotImplementedError("Unsupported cmap table format: %d" % table.format)
     	cp += 1
     
     	# tag.fail
@@ -145,7 +146,7 @@ def makeLookup1():
     		if table.format == 4:
     			table.cmap[cp] = glyphName
     		else:
-    			raise NotImplementedError, "Unsupported cmap table format: %d" % table.format
+    			raise NotImplementedError("Unsupported cmap table format: %d" % table.format)
 
         # bump this up so that the sequence is the same as the lookup 3 font
     	cp += 3
@@ -171,7 +172,7 @@ def makeLookup1():
     script = scriptRecord.Script = Script()
     defaultLangSys = script.DefaultLangSys = DefaultLangSys()
     defaultLangSys.FeatureCount = featureCount
-    defaultLangSys.FeatureIndex = range(defaultLangSys.FeatureCount)
+    defaultLangSys.FeatureIndex = list(range(defaultLangSys.FeatureCount))
     defaultLangSys.ReqFeatureIndex = 65535
     defaultLangSys.LookupOrder = None
     script.LangSysCount = 0
@@ -326,7 +327,7 @@ def makeLookup3():
     		if table.format == 4:
     			table.cmap[cp] = glyphName
     		else:
-    			raise NotImplementedError, "Unsupported cmap table format: %d" % table.format
+    			raise NotImplementedError("Unsupported cmap table format: %d" % table.format)
     	cp += 1
     
     	# tag.alt1,2,3
@@ -347,7 +348,7 @@ def makeLookup3():
     			if table.format == 4:
     				table.cmap[cp] = glyphName
     			else:
-    				raise NotImplementedError, "Unsupported cmap table format: %d" % table.format
+    				raise NotImplementedError("Unsupported cmap table format: %d" % table.format)
     		cp += 1
     	
     # set the glyph order
@@ -371,7 +372,7 @@ def makeLookup3():
     script = scriptRecord.Script = Script()
     defaultLangSys = script.DefaultLangSys = DefaultLangSys()
     defaultLangSys.FeatureCount = featureCount
-    defaultLangSys.FeatureIndex = range(defaultLangSys.FeatureCount)
+    defaultLangSys.FeatureIndex = list(range(defaultLangSys.FeatureCount))
     defaultLangSys.ReqFeatureIndex = 65535
     defaultLangSys.LookupOrder = None
     script.LangSysCount = 0
@@ -474,13 +475,13 @@ def makeJavascriptData():
 
 # build fonts
 
-print "Making lookup type 1 font..."
+print("Making lookup type 1 font...")
 makeLookup1()
 
-print "Making lookup type 3 font..."
+print("Making lookup type 3 font...")
 makeLookup3()
 
 # output javascript data
 
-print "Making javascript data file..."
+print("Making javascript data file...")
 makeJavascriptData()
\ No newline at end of file
diff --git a/layout/reftests/w3c-css/import-tests.py b/layout/reftests/w3c-css/import-tests.py
index 1a631e2bec..bb1db3a8f0 100755
--- a/layout/reftests/w3c-css/import-tests.py
+++ b/layout/reftests/w3c-css/import-tests.py
@@ -80,7 +80,7 @@ def log_output_of(subprocess):
     global gLog
     subprocess.wait()
     if (subprocess.returncode != 0):
-        raise StandardError("error while running subprocess")
+        raise Exception("error while running subprocess")
     gLog.write(subprocess.stdout.readline().rstrip())
 
 def write_log_header():
@@ -124,7 +124,7 @@ def populate_test_files():
 def copy_file(test, srcfile, destname, isSupportFile=False):
     global gDestPath, gLog, gSrcPath
     if not srcfile.startswith(gSrcPath):
-        raise StandardError("Filename " + srcfile + " does not start with " + gSrcPath)
+        raise Exception("Filename " + srcfile + " does not start with " + gSrcPath)
     logname = srcfile[len(gSrcPath):]
     gLog.write("Importing " + to_unix_path_sep(logname) +
                " to " + to_unix_path_sep(destname) + "\n")
@@ -133,7 +133,7 @@ def copy_file(test, srcfile, destname, isSupportFile=False):
     if not os.path.exists(destdir):
         os.makedirs(destdir)
     if os.path.exists(destfile):
-        raise StandardError("file " + destfile + " already exists")
+        raise Exception("file " + destfile + " already exists")
     copy_and_prefix(test, srcfile, destfile, gPrefixedProperties, isSupportFile)
 
 def copy_support_files(test, dirname):
@@ -216,7 +216,7 @@ def add_test_items(srcname):
         else:
             gLog.write("Warning: href attribute found empty in " + srcname + "\n")
     if len(refs) > 1:
-        raise StandardError("Need to add code to specify which reference we want to match.")
+        raise Exception("Need to add code to specify which reference we want to match.")
     for ref in refs:
         tests.append(["==", map_file(srcname), map_file(ref)])
     for notref in notrefs:
@@ -287,7 +287,7 @@ def setup_paths():
     gSrcPath = gArgs[0]
     if not os.path.isdir(gSrcPath) or \
     not os.path.isdir(os.path.join(gSrcPath, ".hg")):
-        raise StandardError("source path does not appear to be a mercurial clone")
+        raise Exception("source path does not appear to be a mercurial clone")
 
     gDestPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "received")
     newSubtrees = []
@@ -339,7 +339,7 @@ def main():
                 listfile.write("\ndefault-preferences {0}\n\n".format(defaultPreferences))
             lastDefaultPreferences = defaultPreferences
         key = 1
-        while not test[key] in gTestFlags.keys() and key < len(test):
+        while not test[key] in list(gTestFlags.keys()) and key < len(test):
             key = key + 1
         testType = test[key - 1]
         testFlags = gTestFlags[test[key]]
diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-line-height-tests.py b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-line-height-tests.py
index 7aa975aaa6..ccc8d2923a 100644
--- a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-line-height-tests.py
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-line-height-tests.py
@@ -10,6 +10,7 @@ reftest.list to the stdout.
 
 from __future__ import unicode_literals
 
+from __future__ import print_function
 TEST_FILE = 'text-emphasis-line-height-{:03}{}.html'
 TEST_TEMPLATE = '''<!DOCTYPE html>
 <meta charset="utf-8">
@@ -62,7 +63,7 @@ def write_file(filename, content):
     with open(filename, 'wb') as f:
         f.write(content.encode('UTF-8'))
 
-print("# START tests from {}".format(__file__))
+print(("# START tests from {}".format(__file__)))
 idx = 0
 for (pos, emphasis_pos, ruby_pos, wms, dir) in POSITIONS:
     idx += 1
@@ -78,5 +79,5 @@ for (pos, emphasis_pos, ruby_pos, wms, dir) in POSITIONS:
                 pos=pos, wm=wm, tag=tag, index=idx, dir=dir,
                 start=start.format(style1=style1, style2=STYLE2), end=end)
             write_file(test_file, content)
-            print("== {} {}".format(test_file, ref_file))
-print("# END tests from {}".format(__file__))
+            print(("== {} {}".format(test_file, ref_file)))
+print(("# END tests from {}".format(__file__)))
diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-position-property-tests.py b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-position-property-tests.py
index 94701b57f2..f843919ba8 100644
--- a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-position-property-tests.py
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-position-property-tests.py
@@ -11,6 +11,7 @@ tests it generated in the format of Mozilla reftest.list to the stdout.
 
 from __future__ import unicode_literals
 
+from __future__ import print_function
 import itertools
 
 TEST_FILE = 'text-emphasis-position-property-{:03}{}.html'
@@ -72,8 +73,8 @@ for wm in WRITING_MODES:
         if wm != "horizontal-tb":
             write_test_files(wm, "sideways", pos1, pos2)
 
-print("# START tests from {}".format(__file__))
+print(("# START tests from {}".format(__file__)))
 reftest_items.sort()
 for item in reftest_items:
     print(item)
-print("# END tests from {}".format(__file__))
+print(("# END tests from {}".format(__file__)))
diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-ruby-tests.py b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-ruby-tests.py
index bb2f9706ad..4db2584a50 100644
--- a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-ruby-tests.py
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-ruby-tests.py
@@ -9,6 +9,7 @@ tests it generated in the format of Mozilla reftest.list to the stdout.
 
 from __future__ import unicode_literals
 
+from __future__ import print_function
 TEST_FILE = 'text-emphasis-ruby-{:03}{}.html'
 TEST_TEMPLATE = '''<!DOCTYPE html>
 <meta charset="utf-8">
@@ -52,7 +53,7 @@ def write_file(filename, content):
     with open(filename, 'wb') as f:
         f.write(content.encode('UTF-8'))
 
-print("# START tests from {}".format(__file__))
+print(("# START tests from {}".format(__file__)))
 idx = 0
 for pos, ref_wm, ruby_pos, subtests in TEST_CASES:
     idx += 1
@@ -65,5 +66,5 @@ for pos, ref_wm, ruby_pos, subtests in TEST_CASES:
         test_content = TEST_TEMPLATE.format(
             wm=wm, pos=pos, index=idx, ruby_pos=ruby_pos, posval=posval)
         write_file(test_file, test_content)
-        print("== {} {}".format(test_file, ref_file))
-print("# END tests from {}".format(__file__))
+        print(("== {} {}".format(test_file, ref_file)))
+print(("# END tests from {}".format(__file__)))
diff --git a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-style-property-tests.py b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-style-property-tests.py
index eb14e83bc5..9ecc609659 100644
--- a/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-style-property-tests.py
+++ b/layout/reftests/w3c-css/submitted/text-decor-3/support/generate-text-emphasis-style-property-tests.py
@@ -10,6 +10,7 @@ tests it generated in the format of Mozilla reftest.list to the stdout.
 
 from __future__ import unicode_literals
 
+from __future__ import print_function
 TEST_FILE = 'text-emphasis-style-property-{:03}{}.html'
 TEST_TEMPLATE = '''<!DOCTYPE html>
 <meta charset="utf-8">
@@ -59,7 +60,7 @@ def write_test_file(idx, suffix, style, code, name=None):
                                               char=get_html_entity(code),
                                               code='U+{:04X}'.format(code),
                                               title=name))
-    print("== {} {}".format(filename, REF_FILE.format(idx)))
+    print(("== {} {}".format(filename, REF_FILE.format(idx))))
 
 idx = 10
 def write_files(style, code):
@@ -77,9 +78,9 @@ def write_files(style, code):
     if shape == 'circle':
         write_test_file(idx, next(suffix), fill, code, fill + ', horizontal')
 
-print("# START tests from {}".format(__file__))
+print(("# START tests from {}".format(__file__)))
 for name, code, _ in DATA_SET:
     write_files(('filled', name), code)
 for name, _, code in DATA_SET:
     write_files(('open', name), code)
-print("# END tests from {}".format(__file__))
+print(("# END tests from {}".format(__file__)))
diff --git a/layout/style/GenerateCSSPropsGenerated.py b/layout/style/GenerateCSSPropsGenerated.py
index 5038e9afe7..18ab142fe4 100644
--- a/layout/style/GenerateCSSPropsGenerated.py
+++ b/layout/style/GenerateCSSPropsGenerated.py
@@ -3,6 +3,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import sys
+import functools
 import string
 import argparse
 import subprocess
@@ -26,7 +27,7 @@ def get_properties(preprocessorHeader):
         property_order = {"longhand": 0, "logical": 0, "shorthand": 1, "alias": 2}
         return property_order[x["proptype"]] - property_order[y["proptype"]]
 
-    properties = sorted(properties, cmp=property_compare)
+    properties = sorted(properties, key=functools.cmp_to_key(property_compare))
 
     for i, p in enumerate(properties):
         p["index"] = i
@@ -62,22 +63,22 @@ def generate_assertions(properties):
             return "eCSSProperty_%s" % p["id"]
     msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
            'properties in nsCSSPropertyID order");')
-    return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
+    return "\n".join([msg % (enum(p), p["index"]) for p in properties])
 
 def generate_idl_name_positions(properties):
     # Skip aliases.
-    ps = filter(lambda p: p["proptype"] is not "alias", properties)
+    ps = [p for p in properties if p["proptype"] is not "alias"]
 
     # Sort alphabetically by IDL name.
-    ps = sorted(ps, key=lambda p: p["idlname"])
+    ps = sorted(ps, key=lambda p: (p["idlname"] is None, p["idlname"] or ''))
 
     # Annotate entries with the sorted position.
     ps = [(p, position) for position, p in enumerate(ps)]
 
     # Sort back to nsCSSPropertyID order.
-    ps = sorted(ps, key=lambda (p, position): p["index"])
+    ps = sorted(ps, key=lambda p_position1: p_position1[0]["index"])
 
-    return ",\n".join(map(lambda (p, position): "  %d" % position, ps))
+    return ",\n".join(["  %d" % p_position[1] for p_position in ps])
 
 def generate(output, cppTemplate, preprocessorHeader):
     cppFile = open(cppTemplate, "r")
diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py
index a85181f9a6..871c265e8f 100644
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, unicode_literals
 
+from __future__ import print_function
 import os
 import re
 import sys
@@ -149,7 +150,7 @@ class ReftestRunner(MozbuildObject):
         import runreftestmulet
 
         if self.substs.get('ENABLE_MARIONETTE') != '1':
-            print(MARIONETTE_DISABLED % self.mozconfig['path'])
+            print((MARIONETTE_DISABLED % self.mozconfig['path']))
             return 1
 
         if not args.profile:
@@ -161,7 +162,7 @@ class ReftestRunner(MozbuildObject):
 
         if os.path.isfile(os.path.join(args.profile, 'extensions',
                                        'httpd@gaiamobile.org')):
-            print(GAIA_PROFILE_IS_DEBUG % args.profile)
+            print((GAIA_PROFILE_IS_DEBUG % args.profile))
             return 1
 
         args.app = self.get_binary_path()
diff --git a/layout/tools/reftest/mach_test_package_commands.py b/layout/tools/reftest/mach_test_package_commands.py
index 197800cf27..b35eee8110 100644
--- a/layout/tools/reftest/mach_test_package_commands.py
+++ b/layout/tools/reftest/mach_test_package_commands.py
@@ -27,7 +27,7 @@ def run_reftest(context, **kwargs):
 
     test_root = os.path.join(context.package_root, 'reftest', 'tests')
     normalize = partial(context.normalize_test_path, test_root)
-    args.tests = map(normalize, args.tests)
+    args.tests = list(map(normalize, args.tests))
 
     return run_reftest_desktop(context, args)
 
diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py
index 40bd8a5ee1..5de242df5d 100644
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -2,7 +2,7 @@ import argparse
 import os
 import sys
 from collections import OrderedDict
-from urlparse import urlparse
+from urllib.parse import urlparse
 
 import mozlog
 
@@ -254,7 +254,7 @@ class ReftestArgumentsParser(argparse.ArgumentParser):
                 return
 
         for test_path in options.tests:
-            for manifest_file, suite in manifests.iteritems():
+            for manifest_file, suite in manifests.items():
                 if os.path.exists(os.path.join(test_path, manifest_file)):
                     options.suite = suite
                     return
diff --git a/layout/tools/reftest/remotereftest.py b/layout/tools/reftest/remotereftest.py
index f871c75861..170237d1f3 100644
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -2,12 +2,13 @@
 # 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 print_function
 import sys
 import os
 import time
 import tempfile
 import traceback
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
 import mozdevice
 import mozinfo
@@ -30,7 +31,7 @@ class RemoteReftestResolver(ReftestResolver):
         elif os.path.exists(os.path.abspath(path)):
             rv = os.path.abspath(path)
         else:
-            print >> sys.stderr, "Could not find manifest %s" % script_abs_path
+            print("Could not find manifest %s" % script_abs_path, file=sys.stderr)
             sys.exit(1)
         return os.path.normpath(rv)
 
@@ -88,7 +89,7 @@ class ReftestServer:
         self._process = self.automation.Process([xpcshell] + args, env = env)
         pid = self._process.pid
         if pid < 0:
-            print "TEST-UNEXPECTED-FAIL | remotereftests.py | Error starting server."
+            print("TEST-UNEXPECTED-FAIL | remotereftests.py | Error starting server.")
             return 2
         self.automation.log.info("INFO | remotereftests.py | Server pid: %d", pid)
 
@@ -108,14 +109,14 @@ class ReftestServer:
             time.sleep(1)
             i += 1
         else:
-            print "TEST-UNEXPECTED-FAIL | remotereftests.py | Timed out while waiting for server startup."
+            print("TEST-UNEXPECTED-FAIL | remotereftests.py | Timed out while waiting for server startup.")
             self.stop()
             return 1
 
     def stop(self):
         if hasattr(self, '_process'):
             try:
-                c = urllib2.urlopen(self.shutdownURL)
+                c = six.moves.urllib.request.urlopen(self.shutdownURL)
                 c.read()
                 c.close()
 
@@ -186,7 +187,7 @@ class RemoteReftest(RefTest):
         paths = [options.xrePath, localAutomation.DIST_BIN, self.automation._product, os.path.join('..', self.automation._product)]
         options.xrePath = self.findPath(paths)
         if options.xrePath == None:
-            print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
+            print("ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name))
             return 1
         paths.append("bin")
         paths.append(os.path.join("..", "bin"))
@@ -199,7 +200,7 @@ class RemoteReftest(RefTest):
             paths.insert(0, options.utilityPath)
         options.utilityPath = self.findPath(paths, xpcshell)
         if options.utilityPath == None:
-            print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name)
+            print("ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name))
             return 1
 
         options.serverProfilePath = tempfile.mkdtemp()
@@ -244,7 +245,7 @@ class RemoteReftest(RefTest):
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
             self._devicemanager.chmodDir(options.remoteProfile)
         except mozdevice.DMError:
-            print "Automation Error: Failed to copy profiledir to device"
+            print("Automation Error: Failed to copy profiledir to device")
             raise
 
         return profile
@@ -256,26 +257,26 @@ class RemoteReftest(RefTest):
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
             self._devicemanager.chmodDir(options.remoteProfile)
         except mozdevice.DMError:
-            print "Automation Error: Failed to copy extra files to device"
+            print("Automation Error: Failed to copy extra files to device")
             raise
 
     def printDeviceInfo(self, printLogcat=False):
         try:
             if printLogcat:
                 logcat = self._devicemanager.getLogcat(filterOutRegexps=fennecLogcatFilters)
-                print ''.join(logcat)
-            print "Device info:"
+                print(''.join(logcat))
+            print("Device info:")
             devinfo = self._devicemanager.getInfo()
             for category in devinfo:
                 if type(devinfo[category]) is list:
-                    print "  %s:" % category
+                    print("  %s:" % category)
                     for item in devinfo[category]:
-                        print "     %s" % item
+                        print("     %s" % item)
                 else:
-                    print "  %s: %s" % (category, devinfo[category])
-            print "Test root: %s" % self._devicemanager.deviceRoot
+                    print("  %s: %s" % (category, devinfo[category]))
+            print("Test root: %s" % self._devicemanager.deviceRoot)
         except mozdevice.DMError:
-            print "WARNING: Error getting device information"
+            print("WARNING: Error getting device information")
 
     def environment(self, **kwargs):
         return self.automation.environment(**kwargs)
@@ -308,8 +309,8 @@ class RemoteReftest(RefTest):
                 self._devicemanager.fileExists(self.remoteLogFile):
             self._devicemanager.getFile(self.remoteLogFile, self.localLogName)
         else:
-            print "WARNING: Unable to retrieve log file (%s) from remote " \
-                "device" % self.remoteLogFile
+            print("WARNING: Unable to retrieve log file (%s) from remote " \
+                "device" % self.remoteLogFile)
         self._devicemanager.removeDir(self.remoteProfile)
         self._devicemanager.removeDir(self.remoteTestRoot)
         RefTest.cleanup(self, profileDir)
@@ -318,12 +319,12 @@ class RemoteReftest(RefTest):
                 os.remove(self.pidFile)
                 os.remove(self.pidFile + ".xpcshell.pid")
             except:
-                print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile
+                print("Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile)
 
 
 def run_test_harness(parser, options):
     if options.dm_trans == 'sut' and options.deviceIP == None:
-        print "Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option"
+        print("Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option")
         return 1
 
     dm_args = {
@@ -343,7 +344,7 @@ def run_test_harness(parser, options):
         dm = dm_cls(**dm_args)
     except mozdevice.DMError:
         traceback.print_exc()
-        print "Automation Error: exception while initializing devicemanager.  Most likely the device is not in a testable state."
+        print("Automation Error: exception while initializing devicemanager.  Most likely the device is not in a testable state.")
         return 1
 
     automation = RemoteAutomation(None)
@@ -359,7 +360,7 @@ def run_test_harness(parser, options):
     expected = options.app.split('/')[-1]
     installed = dm.shellCheckOutput(['pm', 'list', 'packages', expected])
     if expected not in installed:
-        print "%s is not installed on this device" % expected
+        print("%s is not installed on this device" % expected)
         return 1
 
     automation.setAppName(options.app)
@@ -369,7 +370,7 @@ def run_test_harness(parser, options):
     parser.validate(options, reftest)
 
     if mozinfo.info['debug']:
-        print "changing timeout for remote debug reftests from %s to 600 seconds" % options.timeout
+        print("changing timeout for remote debug reftests from %s to 600 seconds" % options.timeout)
         options.timeout = 600
 
     # Hack in a symbolic link for jsreftest
@@ -394,7 +395,7 @@ def run_test_harness(parser, options):
         dm.recordLogcat()
         retVal = reftest.runTests(options.tests, options)
     except:
-        print "Automation Error: Exception caught while running tests"
+        print("Automation Error: Exception caught while running tests")
         traceback.print_exc()
         retVal = 1
 
diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py
index 7061b16ca5..7ea465d48e 100644
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -6,6 +6,7 @@
 Runs the reftest test harness.
 """
 
+from __future__ import print_function
 import collections
 import json
 import multiprocessing
@@ -37,7 +38,7 @@ from mozscreenshot import printstatus, dump_screen
 try:
     from marionette_driver.addons import Addons
     from marionette_harness import Marionette
-except ImportError, e:
+except ImportError as e:
     # Defer ImportError until attempt to use Marionette
     def reraise(*args, **kwargs):
         raise(e)
@@ -85,12 +86,12 @@ class ReftestThread(threading.Thread):
 
     def run(self):
         with printLock:
-            print "Starting thread with", self.cmdargs
+            print("Starting thread with", self.cmdargs)
             sys.stdout.flush()
         process = subprocess.Popen(self.cmdargs, stdout=subprocess.PIPE)
         for chunk in self.chunkForMergedOutput(process.stdout):
             with printLock:
-                print chunk,
+                print(chunk, end=' ')
                 sys.stdout.flush()
         self.retcode = process.wait()
 
@@ -194,7 +195,7 @@ class ReftestResolver(object):
                     manifests[manifest] = set()
                 manifests[manifest].add(filter_str)
 
-        for key in manifests.iterkeys():
+        for key in manifests.keys():
             if None in manifests[key]:
                 manifests[key] = None
             else:
@@ -303,7 +304,7 @@ class RefTest(object):
         for v in options.extraPrefs:
             thispref = v.split('=')
             if len(thispref) < 2:
-                print "Error: syntax error in --setpref=" + v
+                print("Error: syntax error in --setpref=" + v)
                 sys.exit(1)
             prefs[thispref[0]] = thispref[1].strip()
 
@@ -362,7 +363,7 @@ class RefTest(object):
         for v in options.environment:
             ix = v.find("=")
             if ix <= 0:
-                print "Error: syntax error in --setenv=" + v
+                print("Error: syntax error in --setenv=" + v)
                 return None
             browserEnv[v[:ix]] = v[ix + 1:]
 
@@ -498,11 +499,11 @@ class RefTest(object):
                     threadMatches.group('total') if threadMatches else 0)
                 summaryObj['total'] += amount
 
-        print 'REFTEST INFO | Result summary:'
+        print('REFTEST INFO | Result summary:')
         for (summaryObj, (text, categories)) in zip(summaryObjects, summaryLines):
             details = ', '.join(["%d %s" % (summaryObj[attribute], description) for (
                 attribute, description) in categories])
-            print 'REFTEST INFO | ' + text + ': ' + str(summaryObj['total']) + ' (' + details + ')'
+            print('REFTEST INFO | ' + text + ': ' + str(summaryObj['total']) + ' (' + details + ')')
 
         return int(any(t.retcode != 0 for t in threads))
 
diff --git a/layout/tools/reftest/runreftestb2g.py b/layout/tools/reftest/runreftestb2g.py
index 6a6346ece0..5dcba6d420 100644
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -2,7 +2,8 @@
 # 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/.
 
-import ConfigParser
+from __future__ import print_function
+import six.moves.configparser
 import os
 import sys
 import tempfile
@@ -25,7 +26,7 @@ from marionette_harness import Marionette
 from mozdevice import DeviceManagerADB, DMError
 
 
-class ProfileConfigParser(ConfigParser.RawConfigParser):
+class ProfileConfigParser(six.moves.configparser.RawConfigParser):
     """Subclass of RawConfigParser that outputs .ini files in the exact
        format expected for profiles.ini, which is slightly different
        than the default format.
@@ -36,7 +37,7 @@ class ProfileConfigParser(ConfigParser.RawConfigParser):
 
     def write(self, fp):
         if self._defaults:
-            fp.write("[%s]\n" % ConfigParser.DEFAULTSECT)
+            fp.write("[%s]\n" % six.moves.configparser.DEFAULTSECT)
             for (key, value) in self._defaults.items():
                 fp.write("%s=%s\n" % (key, str(value).replace('\n', '\n\t')))
             fp.write("\n")
@@ -84,7 +85,7 @@ class B2GRemoteReftest(RefTest):
             try:
                 self._devicemanager.getFile(self.remoteLogFile, self.localLogName)
             except:
-                print "ERROR: We were not able to retrieve the info from %s" % self.remoteLogFile
+                print("ERROR: We were not able to retrieve the info from %s" % self.remoteLogFile)
                 sys.exit(5)
 
         # Delete any bundled extensions
@@ -121,7 +122,7 @@ class B2GRemoteReftest(RefTest):
                 os.remove(self.pidFile)
                 os.remove(self.pidFile + ".xpcshell.pid")
             except:
-                print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile
+                print("Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile)
 
     def findPath(self, paths, filename = None):
         for path in paths:
@@ -158,7 +159,7 @@ class B2GRemoteReftest(RefTest):
                  os.path.join('..', self.automation._product)]
         options.xrePath = self.findPath(paths)
         if options.xrePath == None:
-            print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
+            print("ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name))
             sys.exit(1)
         paths.append("bin")
         paths.append(os.path.join("..", "bin"))
@@ -169,7 +170,7 @@ class B2GRemoteReftest(RefTest):
 
         options.utilityPath = self.findPath(paths, xpcshell)
         if options.utilityPath == None:
-            print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name)
+            print("ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name))
             sys.exit(1)
 
         xpcshell = os.path.join(options.utilityPath, xpcshell)
@@ -269,7 +270,7 @@ class B2GRemoteReftest(RefTest):
         try:
             self._devicemanager.pushDir(profileDir, self.remoteProfile)
         except DMError:
-            print "Automation Error: Unable to copy profile to device."
+            print("Automation Error: Unable to copy profile to device.")
             raise
 
         # Copy the extensions to the B2G bundles dir.
@@ -282,7 +283,7 @@ class B2GRemoteReftest(RefTest):
         try:
             self._devicemanager.pushDir(extensionDir, self.bundlesDir)
         except DMError:
-            print "Automation Error: Unable to copy extensions to device."
+            print("Automation Error: Unable to copy extensions to device.")
             raise
 
         self.updateProfilesIni(self.remoteProfile)
@@ -296,7 +297,7 @@ class B2GRemoteReftest(RefTest):
         try:
             self._devicemanager.pushDir(profileDir, options.remoteProfile)
         except DMError:
-            print "Automation Error: Failed to copy extra files to device"
+            print("Automation Error: Failed to copy extra files to device")
             raise
 
     def environment(self, **kwargs):
@@ -375,7 +376,7 @@ def run_test_harness(parser, options):
         width = int(parts[0].split(':')[1])
         height = int(parts[1].split(':')[1])
         if (width < 1366 or height < 1050):
-            print "ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height)
+            print("ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (width, height))
             return 1
 
     auto.setProduct("b2g")
@@ -406,7 +407,7 @@ def run_test_harness(parser, options):
 
         retVal = reftest.runTests(options.tests, options)
     except:
-        print "Automation Error: Exception caught while running tests"
+        print("Automation Error: Exception caught while running tests")
         traceback.print_exc()
         reftest.stopWebServer(options)
         try:
diff --git a/mach b/mach
index 1759179a33..93efcbee5f 100755
--- a/mach
+++ b/mach
@@ -22,12 +22,13 @@ def ancestors(path):
             break
 
 def load_mach(dir_path, mach_path):
-    import imp
-    with open(mach_path, 'r') as fh:
-        imp.load_module('mach_bootstrap', fh, mach_path,
-                        ('.py', 'r', imp.PY_SOURCE))
-    import mach_bootstrap
-    return mach_bootstrap.bootstrap(dir_path)
+    import importlib.util
+    spec = importlib.util.spec_from_file_location('mach_bootstrap', mach_path)
+    module = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(module)
+    import sys
+    sys.modules['mach_bootstrap'] = module
+    return module.bootstrap(dir_path)
 
 
 def check_and_get_mach(dir_path):
@@ -59,7 +60,7 @@ def get_mach():
                 # its default locations.
                 #
                 # Note: subprocess requires native strings in os.environ on Windows
-                os.environ[b'MOZCONFIG'] = str(info['mozconfig'])
+                os.environ['MOZCONFIG'] = str(info['mozconfig'])
 
             if 'topsrcdir' in info:
                 # Continue searching for mach_bootstrap in the source directory.
diff --git a/mailnews/extensions/fts3/data/generate_table.py b/mailnews/extensions/fts3/data/generate_table.py
index f6b0126856..3a2b0eeef5 100644
--- a/mailnews/extensions/fts3/data/generate_table.py
+++ b/mailnews/extensions/fts3/data/generate_table.py
@@ -36,18 +36,19 @@
 #
 # ***** END LICENSE BLOCK *****
 
+from __future__ import print_function
 import re
 
 def printTable(f, t):
 	i = f
 	while i <= t:
 		c = array[i]
-		print "0x%04x," % c,
+		print("0x%04x," % c, end=' ')
 		i = i + 1
 		if not i % 8:
-			print "\n\t",
+			print("\n\t", end=' ')
 
-print '''/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+print('''/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
@@ -86,7 +87,7 @@ print '''/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset:
  * ***** END LICENSE BLOCK ***** */
 
 /* THIS FILE IS GENERATED BY generate_table.py.  DON'T EDIT THIS */
-'''
+''')
 
 p = re.compile('([0-9A-F]{4,5})(?:\.\.([0-9A-F]{4,5}))?[=\>]([0-9A-F]{4,5})?')
 G_FROM = 1
@@ -224,10 +225,10 @@ while i < maxmapping:
 			continue
 
 		if needTerm:
-			print "};\n"
+			print("};\n")
 		globalTable.append("gNormalizeTable%04x" % i)
-		print "static const unsigned short gNormalizeTable%04x[] = {\n\t" % i,
-		print "/* U+%04x */\n\t" % i,
+		print("static const unsigned short gNormalizeTable%04x[] = {\n\t" % i, end=' ')
+		print("/* U+%04x */\n\t" % i, end=' ')
 		needTerm = True
         # Decomposition does not case-fold, so we want to compensate by
         # performing a lookup here.  Because decomposition chains can be
@@ -239,20 +240,20 @@ while i < maxmapping:
         if c >= 0x41 and c <= 0x5a:
                 raise Exception('got an uppercase character somehow: %x => %x'
                                 % (i, c))
-	print "0x%04x," % c,
+	print("0x%04x," % c, end=' ')
 	i = i + 1
 	if not i % 8:
-		print "\n\t",
+		print("\n\t", end=' ')
 
-print "};\n\nstatic const unsigned short* gNormalizeTable[] = {",
+print("};\n\nstatic const unsigned short* gNormalizeTable[] = {", end=' ')
 i = 0
 while i < (maxmapping / sizePerTable):
 	if not i % 4:
-		print "\n\t",
-	print globalTable[i] + ",", 
+		print("\n\t", end=' ')
+	print(globalTable[i] + ",", end=' ') 
 	i += 1
 
-print '''
+print('''
 };
 
 unsigned int normalize_character(const unsigned int c)
@@ -261,4 +262,4 @@ unsigned int normalize_character(const unsigned int c)
     return c;
   return gNormalizeTable[c >> 6][c & 0x3f];
 }
-'''
+''')
diff --git a/media/libaom/cmakeparser.py b/media/libaom/cmakeparser.py
index cb2686a618..b54785de90 100644
--- a/media/libaom/cmakeparser.py
+++ b/media/libaom/cmakeparser.py
@@ -1,6 +1,7 @@
 # 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 print_function
 from pyparsing import (CharsNotIn, Group, Forward, Literal, Suppress, Word,
                        QuotedString, ZeroOrMore, alphas, alphanums)
 from string import Template
@@ -36,8 +37,8 @@ def match_block(command, parsed, start):
             depth -= 1
         end = end + 1
         if end == len(parsed):
-            print('error: eof when trying to match block statement: %s'
-                  % parsed[start])
+            print(('error: eof when trying to match block statement: %s'
+                  % parsed[start]))
     return end
 
 
@@ -67,8 +68,8 @@ def parse_if(parsed, start):
             depth -= 1
         end = end + 1
         if end == len(parsed):
-            print('error: eof when trying to match if statement: %s'
-                  % parsed[start])
+            print(('error: eof when trying to match if statement: %s'
+                  % parsed[start]))
     condition.append(parsed[start:end])
     conditions.append(condition)
     return end, conditions
@@ -125,17 +126,17 @@ def evaluate(variables, cache_variables, parsed):
         elif command == 'include':
             if arguments:
                 try:
-                    print('including: %s' % arguments[0])
+                    print(('including: %s' % arguments[0]))
                     sources.extend(parse(variables, cache_variables, arguments[0]))
                 except IOError:
-                    print('warning: could not include: %s' % arguments[0])
+                    print(('warning: could not include: %s' % arguments[0]))
         elif command == 'list':
             try:
                 action = arguments[0]
                 variable = arguments[1]
                 values = arguments[2:]
                 if action == 'APPEND':
-                    if not variables.has_key(variable):
+                    if variable not in variables:
                         variables[variable] = ' '.join(values)
                     else:
                         variables[variable] += ' ' + ' '.join(values)
@@ -145,7 +146,7 @@ def evaluate(variables, cache_variables, parsed):
             variable = arguments[0]
             value = arguments[2]
             # Allow options to be override without changing CMake files
-            if not variables.has_key(variable):
+            if variable not in variables:
                 variables[variable] = value
         elif command == 'return':
             return False, sources
@@ -156,7 +157,7 @@ def evaluate(variables, cache_variables, parsed):
             try:
                 cache = values.index('CACHE')
                 values = values[0:cache]
-                if not variables.has_key(variable):
+                if variable not in variables:
                     variables[variable] = ' '.join(values)
                 cache_variables.append(variable)
             except ValueError:
@@ -193,7 +194,7 @@ def evaluate(variables, cache_variables, parsed):
             for source in arguments[1:]:
                 sources.extend(source.split(' '))
         elif command == 'MOZDEBUG':
-            print('>>>> MOZDEBUG: %s' % ' '.join(arguments))
+            print(('>>>> MOZDEBUG: %s' % ' '.join(arguments)))
         i += 1
     return True, sources
 
diff --git a/media/libaom/generate_sources_mozbuild.py b/media/libaom/generate_sources_mozbuild.py
index b8ed07b1f7..ef3c088d5a 100644
--- a/media/libaom/generate_sources_mozbuild.py
+++ b/media/libaom/generate_sources_mozbuild.py
@@ -1,6 +1,7 @@
 # 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 print_function
 import cmakeparser as cp
 
 import copy
@@ -97,7 +98,7 @@ if __name__ == '__main__':
         ('x86_64', 'win', 'mingw64', False),
     ]
     for cpu, system, arch, generate_sources in platforms:
-        print('Running CMake for %s (%s)' % (cpu, system))
+        print(('Running CMake for %s (%s)' % (cpu, system)))
         variables = shared_variables.copy()
         variables['AOM_TARGET_CPU'] = cpu
 
@@ -123,23 +124,23 @@ if __name__ == '__main__':
         # have to generate sources for each combination.
         if generate_sources:
             # Remove spurious sources and perl files
-            sources = filter(lambda x: x.startswith(AOM_DIR), sources)
-            sources = filter(lambda x: not x.endswith('.pl'), sources)
+            sources = [x for x in sources if x.startswith(AOM_DIR)]
+            sources = [x for x in sources if not x.endswith('.pl')]
 
             # Filter out exports
-            exports = filter(lambda x: re.match(os.path.join(AOM_DIR, '(aom|aom_mem|aom_ports|aom_scale)/.*h$'), x), sources)
-            exports = filter(lambda x: not re.search('(internal|src)', x), exports)
-            exports = filter(lambda x: not re.search('(emmintrin_compat.h|mem_.*|msvc.h|aom_once.h)$', x), exports)
+            exports = [x for x in sources if re.match(os.path.join(AOM_DIR, '(aom|aom_mem|aom_ports|aom_scale)/.*h$'), x)]
+            exports = [x for x in exports if not re.search('(internal|src)', x)]
+            exports = [x for x in exports if not re.search('(emmintrin_compat.h|mem_.*|msvc.h|aom_once.h)$', x)]
 
             for export in exports:
                 sources.remove(export)
 
             # Remove header files
-            sources = sorted(filter(lambda x: not x.endswith('.h'), sources))
+            sources = sorted([x for x in sources if not x.endswith('.h')])
 
             # The build system is unhappy if two files have the same prefix
             # In libaom, sometimes .asm and .c files share the same prefix
-            for i in xrange(len(sources) - 1):
+            for i in range(len(sources) - 1):
                 if sources[i].endswith('.asm'):
                     if os.path.splitext(sources[i])[0] == os.path.splitext(sources[i + 1])[0]:
                         old = sources[i]
diff --git a/media/libaom/src/test/gviz_api.py b/media/libaom/src/test/gviz_api.py
index d3a443dabf..eb0092264f 100755
--- a/media/libaom/src/test/gviz_api.py
+++ b/media/libaom/src/test/gviz_api.py
@@ -213,7 +213,7 @@ class DataTable(object):
           (len(value) == 3 and not isinstance(value[2], dict))):
         raise DataTableException("Wrong format for value and formatting - %s." %
                                  str(value))
-      if not isinstance(value[1], types.StringTypes + (types.NoneType,)):
+      if not isinstance(value[1], (str,) + (type(None),)):
         raise DataTableException("Formatted value is not string, given %s." %
                                  type(value[1]))
       js_value = DataTable.CoerceValue(value[0], value_type)
@@ -226,12 +226,12 @@ class DataTable(object):
       return bool(value)
 
     elif value_type == "number":
-      if isinstance(value, (int, long, float)):
+      if isinstance(value, (int, int, float)):
         return value
       raise DataTableException("Wrong type %s when expected number" % t_value)
 
     elif value_type == "string":
-      if isinstance(value, unicode):
+      if isinstance(value, str):
         return value
       else:
         return str(value).decode("utf-8")
@@ -296,7 +296,7 @@ class DataTable(object):
                             datetime.date,
                             datetime.time)):
       return str(value)
-    elif isinstance(value, unicode):
+    elif isinstance(value, str):
       return value
     elif isinstance(value, bool):
       return str(value).lower()
@@ -329,17 +329,17 @@ class DataTable(object):
     if not description:
       raise DataTableException("Description error: empty description given")
 
-    if not isinstance(description, (types.StringTypes, tuple)):
+    if not isinstance(description, ((str,), tuple)):
       raise DataTableException("Description error: expected either string or "
                                "tuple, got %s." % type(description))
 
-    if isinstance(description, types.StringTypes):
+    if isinstance(description, (str,)):
       description = (description,)
 
     # According to the tuple's length, we fill the keys
     # We verify everything is of type string
     for elem in description[:3]:
-      if not isinstance(elem, types.StringTypes):
+      if not isinstance(elem, (str,)):
         raise DataTableException("Description error: expected tuple of "
                                  "strings, current element of type %s." %
                                  type(elem))
@@ -456,7 +456,7 @@ class DataTable(object):
       -- second 'b' is the label, and {} is the custom properties field.
     """
     # For the recursion step, we check for a scalar object (string or tuple)
-    if isinstance(table_description, (types.StringTypes, tuple)):
+    if isinstance(table_description, ((str,), tuple)):
       parsed_col = DataTable.ColumnTypeParser(table_description)
       parsed_col["depth"] = depth
       parsed_col["container"] = "scalar"
@@ -491,9 +491,9 @@ class DataTable(object):
     # dictionary).
     # NOTE: this way of differentiating might create ambiguity. See docs.
     if (len(table_description) != 1 or
-        (isinstance(table_description.keys()[0], types.StringTypes) and
-         isinstance(table_description.values()[0], tuple) and
-         len(table_description.values()[0]) < 4)):
+        (isinstance(list(table_description.keys())[0], (str,)) and
+         isinstance(list(table_description.values())[0], tuple) and
+         len(list(table_description.values())[0]) < 4)):
       # This is the most inner dictionary. Parsing types.
       columns = []
       # We sort the items, equivalent to sort the keys since they are unique
@@ -509,11 +509,11 @@ class DataTable(object):
         columns.append(parsed_col)
       return columns
     # This is an outer dictionary, must have at most one key.
-    parsed_col = DataTable.ColumnTypeParser(table_description.keys()[0])
+    parsed_col = DataTable.ColumnTypeParser(list(table_description.keys())[0])
     parsed_col["depth"] = depth
     parsed_col["container"] = "dict"
     return ([parsed_col] +
-            DataTable.TableDescriptionParser(table_description.values()[0],
+            DataTable.TableDescriptionParser(list(table_description.values())[0],
                                              depth=depth + 1))
 
   @property
@@ -622,7 +622,7 @@ class DataTable(object):
       return
 
     # We have a dictionary in an inner depth level.
-    if not data.keys():
+    if not list(data.keys()):
       # In case this is an empty dictionary, we add a record with the columns
       # filled only until this point.
       self.__data.append(prev_col_values)
@@ -655,12 +655,12 @@ class DataTable(object):
       return self.__data
 
     proper_sort_keys = []
-    if isinstance(order_by, types.StringTypes) or (
+    if isinstance(order_by, (str,)) or (
         isinstance(order_by, tuple) and len(order_by) == 2 and
         order_by[1].lower() in ["asc", "desc"]):
       order_by = (order_by,)
     for key in order_by:
-      if isinstance(key, types.StringTypes):
+      if isinstance(key, (str,)):
         proper_sort_keys.append((key, 1))
       elif (isinstance(key, (list, tuple)) and len(key) == 2 and
             key[1].lower() in ("asc", "desc")):
diff --git a/media/libaom/src/test/visual_metrics.py b/media/libaom/src/test/visual_metrics.py
index 9055feb334..4a8cb6a650 100755
--- a/media/libaom/src/test/visual_metrics.py
+++ b/media/libaom/src/test/visual_metrics.py
@@ -13,6 +13,7 @@
 """Converts video encoding result data from text files to visualization
 data source."""
 
+from __future__ import print_function
 __author__ = "jzern@google.com (James Zern),"
 __author__ += "jimbankoski@google.com (Jim Bankoski)"
 
@@ -457,10 +458,10 @@ def HandleFiles(variables):
     for i in range(len(dirs)):
       formatters = "%s   formatter.format(better, %d);" % (formatters, i+1)
 
-  print FillForm(page_template, vars())
+  print(FillForm(page_template, vars()))
   return
 
 if len(sys.argv) < 3:
-  print HandleFiles.__doc__
+  print(HandleFiles.__doc__)
 else:
   HandleFiles(sys.argv)
diff --git a/media/libaom/src/tools/aggregate_entropy_stats.py b/media/libaom/src/tools/aggregate_entropy_stats.py
index 7cb4d18e18..ac61dbe0f5 100644
--- a/media/libaom/src/tools/aggregate_entropy_stats.py
+++ b/media/libaom/src/tools/aggregate_entropy_stats.py
@@ -14,6 +14,7 @@ python ./aggregate_entropy_stats.py [dir of stats files] [keyword of filenames]
  [filename of final stats]
 """
 
+from __future__ import print_function
 __author__ = "yuec@google.com"
 
 import os
diff --git a/media/libaom/src/tools/cpplint.py b/media/libaom/src/tools/cpplint.py
index e3ebde2f5a..1ff0053cb3 100755
--- a/media/libaom/src/tools/cpplint.py
+++ b/media/libaom/src/tools/cpplint.py
@@ -512,7 +512,7 @@ _ALT_TOKEN_REPLACEMENT = {
 # False positives include C-style multi-line comments and multi-line strings
 # but those have always been troublesome for cpplint.
 _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
-    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+    r'[ =()](' + ('|'.join(list(_ALT_TOKEN_REPLACEMENT.keys()))) + r')(?=[ (]|$)')
 
 
 # These constants define types of headers for use with
@@ -952,7 +952,7 @@ class _CppLintState(object):
 
   def PrintErrorCounts(self):
     """Print a summary of errors by category, and the total."""
-    for category, count in self.errors_by_category.iteritems():
+    for category, count in self.errors_by_category.items():
       sys.stderr.write('Category \'%s\' errors found: %d\n' %
                        (category, count))
     sys.stdout.write('Total errors found: %d\n' % self.error_count)
@@ -1529,7 +1529,7 @@ def FindEndOfExpressionInLine(line, startpos, stack):
     On finding an unclosed expression: (-1, None)
     Otherwise: (-1, new stack at end of this line)
   """
-  for i in xrange(startpos, len(line)):
+  for i in range(startpos, len(line)):
     char = line[i]
     if char in '([{':
       # Found start of parenthesized expression, push to expression stack
@@ -1758,7 +1758,7 @@ def CheckForCopyright(filename, lines, error):
 
   # We'll say it should occur by line 10. Don't forget there's a
   # placeholder line at the front.
-  for line in xrange(1, min(len(lines), 11)):
+  for line in range(1, min(len(lines), 11)):
     if re.search(r'Copyright', lines[line], re.I): break
   else:                       # means no copyright line was found
     error(filename, 0, 'legal/copyright', 5,
@@ -1960,7 +1960,7 @@ def CheckForHeaderGuard(filename, clean_lines, error):
   # contain any "//" comments at all, it could be that the compiler
   # only wants "/**/" comments, look for those instead.
   no_single_line_comments = True
-  for i in xrange(1, len(raw_lines) - 1):
+  for i in range(1, len(raw_lines) - 1):
     line = raw_lines[i]
     if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line):
       no_single_line_comments = False
@@ -2301,7 +2301,7 @@ class _ClassInfo(_BlockInfo):
     # If there is a DISALLOW macro, it should appear near the end of
     # the class.
     seen_last_thing_in_class = False
-    for i in xrange(linenum - 1, self.starting_linenum, -1):
+    for i in range(linenum - 1, self.starting_linenum, -1):
       match = Search(
           r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' +
           self.name + r'\)',
@@ -3083,7 +3083,7 @@ def CheckForFunctionLengths(filename, clean_lines, linenum,
 
   if starting_func:
     body_found = False
-    for start_linenum in xrange(linenum, clean_lines.NumLines()):
+    for start_linenum in range(linenum, clean_lines.NumLines()):
       start_line = lines[start_linenum]
       joined_line += ' ' + start_line.lstrip()
       if Search(r'(;|})', start_line):  # Declarations and trivial functions
@@ -3540,7 +3540,7 @@ def _IsType(clean_lines, nesting_state, expr):
       continue
 
     # Look for typename in the specified range
-    for i in xrange(first_line, last_line + 1, 1):
+    for i in range(first_line, last_line + 1, 1):
       if Search(typename_pattern, clean_lines.elided[i]):
         return True
     block_index -= 1
@@ -3604,7 +3604,7 @@ def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error):
     trailing_text = ''
     if endpos > -1:
       trailing_text = endline[endpos:]
-    for offset in xrange(endlinenum + 1,
+    for offset in range(endlinenum + 1,
                          min(endlinenum + 3, clean_lines.NumLines() - 1)):
       trailing_text += clean_lines.elided[offset]
     # We also suppress warnings for `uint64_t{expression}` etc., as the style
@@ -4158,7 +4158,7 @@ def CheckCheck(filename, clean_lines, linenum, error):
     expression = lines[linenum][start_pos + 1:end_pos - 1]
   else:
     expression = lines[linenum][start_pos + 1:]
-    for i in xrange(linenum + 1, end_line):
+    for i in range(linenum + 1, end_line):
       expression += lines[i]
     expression += last_line[0:end_pos - 1]
 
@@ -4286,7 +4286,7 @@ def GetLineWidth(line):
     The width of the line in column positions, accounting for Unicode
     combining characters and wide characters.
   """
-  if isinstance(line, unicode):
+  if isinstance(line, str):
     width = 0
     for uc in unicodedata.normalize('NFC', line):
       if unicodedata.east_asian_width(uc) in ('W', 'F'):
@@ -4622,7 +4622,7 @@ def _GetTextInside(text, start_pattern):
 
   # Give opening punctuations to get the matching close-punctuations.
   matching_punctuation = {'(': ')', '{': '}', '[': ']'}
-  closing_punctuation = set(matching_punctuation.itervalues())
+  closing_punctuation = set(matching_punctuation.values())
 
   # Find the position to start extracting text.
   match = re.search(start_pattern, text, re.M)
@@ -4941,7 +4941,7 @@ def IsDerivedFunction(clean_lines, linenum):
     virt-specifier.
   """
   # Scan back a few lines for start of current function
-  for i in xrange(linenum, max(-1, linenum - 10), -1):
+  for i in range(linenum, max(-1, linenum - 10), -1):
     match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
     if match:
       # Look for "override" after the matching closing parenthesis
@@ -4962,7 +4962,7 @@ def IsOutOfLineMethodDefinition(clean_lines, linenum):
     True if current line contains an out-of-line method definition.
   """
   # Scan back a few lines for start of current function
-  for i in xrange(linenum, max(-1, linenum - 10), -1):
+  for i in range(linenum, max(-1, linenum - 10), -1):
     if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
       return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None
   return False
@@ -4978,7 +4978,7 @@ def IsInitializerList(clean_lines, linenum):
     True if current line appears to be inside constructor initializer
     list, False otherwise.
   """
-  for i in xrange(linenum, 1, -1):
+  for i in range(linenum, 1, -1):
     line = clean_lines.elided[i]
     if i == linenum:
       remove_function_body = Match(r'^(.*)\{\s*$', line)
@@ -5079,7 +5079,7 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
           # Found the matching < on an earlier line, collect all
           # pieces up to current line.
           line = ''
-          for i in xrange(startline, linenum + 1):
+          for i in range(startline, linenum + 1):
             line += clean_lines.elided[i].strip()
 
   # Check for non-const references in function parameters.  A single '&' may
@@ -5103,7 +5103,7 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
   # appear inside the second set of parentheses on the current line as
   # opposed to the first set.
   if linenum > 0:
-    for i in xrange(linenum - 1, max(0, linenum - 10), -1):
+    for i in range(linenum - 1, max(0, linenum - 10), -1):
       previous_line = clean_lines.elided[i]
       if not Search(r'[),]\s*$', previous_line):
         break
@@ -5134,7 +5134,7 @@ def CheckForNonConstReference(filename, clean_lines, linenum,
     # Don't see an allowed function on this line.  Actually we
     # didn't see any function name on this line, so this is likely a
     # multi-line parameter list.  Try a bit harder to catch this case.
-    for i in xrange(2):
+    for i in range(2):
       if (linenum > i and
           Search(allowed_functions, clean_lines.elided[linenum - i - 1])):
         return
@@ -5297,7 +5297,7 @@ def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
   # Try expanding current context to see if we one level of
   # parentheses inside a macro.
   if linenum > 0:
-    for i in xrange(linenum - 1, max(0, linenum - 5), -1):
+    for i in range(linenum - 1, max(0, linenum - 5), -1):
       context = clean_lines.elided[i] + context
   if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):
     return False
@@ -5516,7 +5516,7 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
   required = {}  # A map of header name to linenumber and the template entity.
                  # Example of required: { '<functional>': (1219, 'less<>') }
 
-  for linenum in xrange(clean_lines.NumLines()):
+  for linenum in range(clean_lines.NumLines()):
     line = clean_lines.elided[linenum]
     if not line or line[0] == '#':
       continue
@@ -5570,7 +5570,7 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
 
   # include_dict is modified during iteration, so we iterate over a copy of
   # the keys.
-  header_keys = include_dict.keys()
+  header_keys = list(include_dict.keys())
   for header in header_keys:
     (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
     fullpath = common_path + header
@@ -5652,7 +5652,7 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error):
   end_col = -1
   end_line = -1
   start_col = len(virtual.group(2))
-  for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())):
+  for start_line in range(linenum, min(linenum + 3, clean_lines.NumLines())):
     line = clean_lines.elided[start_line][start_col:]
     parameter_list = Match(r'^([^(]*)\(', line)
     if parameter_list:
@@ -5667,7 +5667,7 @@ def CheckRedundantVirtual(filename, clean_lines, linenum, error):
 
   # Look for "override" or "final" after the parameter list
   # (possibly on the next few lines).
-  for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())):
+  for i in range(end_line, min(end_line + 3, clean_lines.NumLines())):
     line = clean_lines.elided[i][end_col:]
     match = Search(r'\b(override|final)\b', line)
     if match:
@@ -5924,7 +5924,7 @@ def ProcessFileData(filename, file_extension, lines, error,
   if IsHeaderExtension(file_extension):
     CheckForHeaderGuard(filename, clean_lines, error)
 
-  for line in xrange(clean_lines.NumLines()):
+  for line in range(clean_lines.NumLines()):
     ProcessLine(filename, file_extension, clean_lines, line,
                 include_state, function_state, nesting_state, error,
                 extra_check_functions)
diff --git a/media/libaom/src/tools/gen_constrained_tokenset.py b/media/libaom/src/tools/gen_constrained_tokenset.py
index 5d12ee1ef5..5fc42656f9 100755
--- a/media/libaom/src/tools/gen_constrained_tokenset.py
+++ b/media/libaom/src/tools/gen_constrained_tokenset.py
@@ -20,6 +20,7 @@ is first solved, and then the {alpha, beta} pair is used to generate
 the probabilities for the rest of the nodes.
 """
 
+from __future__ import print_function
 import heapq
 import sys
 import numpy as np
@@ -108,7 +109,7 @@ def main(bits=15, first_token=1):
   for q in range(1, 256):
     parray = get_quantized_spareto(q / 256., beta, bits, first_token)
     assert parray.sum() == 2**bits
-    print '{', ', '.join('%d' % i for i in parray), '},'
+    print('{', ', '.join('%d' % i for i in parray), '},')
 
 
 if __name__ == '__main__':
diff --git a/media/libaom/src/tools/gop_bitrate/analyze_data.py b/media/libaom/src/tools/gop_bitrate/analyze_data.py
index 4e006b9220..611cc68cdd 100644
--- a/media/libaom/src/tools/gop_bitrate/analyze_data.py
+++ b/media/libaom/src/tools/gop_bitrate/analyze_data.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 with open('experiment.txt', 'r') as file:
     lines = file.readlines()
     curr_filename = ''
diff --git a/media/libaom/src/tools/gop_bitrate/python/bitrate_accuracy.py b/media/libaom/src/tools/gop_bitrate/python/bitrate_accuracy.py
index 2a5da6a794..f1e8ea9c60 100644
--- a/media/libaom/src/tools/gop_bitrate/python/bitrate_accuracy.py
+++ b/media/libaom/src/tools/gop_bitrate/python/bitrate_accuracy.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import numpy as np
 
 # Model A only.
@@ -15,7 +16,7 @@ def pinv_solution(A, mv, B):
     new_A = np.concatenate((A, mv), axis=1)
     new_A_inv = np.linalg.pinv(new_A)
     new_x = np.matmul(new_A_inv, B)
-    print("pinv solution:", new_x[0][0], new_x[1][0])
+    print(("pinv solution:", new_x[0][0], new_x[1][0]))
     return (new_x[0][0], new_x[1][0])
 
 # Model A only.
@@ -160,7 +161,7 @@ def print_solutions(file_path):
         all_zeros = not A.any()
         if all_zeros:
             continue
-        print("update type:", update[0][0])
+        print(("update type:", update[0][0]))
         x_ls = lstsq_solution(A, B)
         x_a = minimize_percentage_error_model_a(A, B)
         x_b = minimize_percentage_error_model_b(A, mv, B)
@@ -175,10 +176,10 @@ def print_solutions(file_path):
         baseline_squared_error_b = average_squared_error_model_b(A, mv, B, [1, 1])[0]
 
         print("model,\tframe_coeff,\tmv_coeff,\terror,\tbaseline_error")
-        print("Model A %_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(percent_error_a) + ",\t" + str(baseline_percent_error_a))
-        print("Model A sq_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(squared_error_a) + ",\t" + str(baseline_squared_error_a))
-        print("Model B %_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(percent_error_b) + ",\t" + str(baseline_percent_error_b))
-        print("Model B sq_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(squared_error_b) + ",\t" + str(baseline_squared_error_b))
+        print(("Model A %_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(percent_error_a) + ",\t" + str(baseline_percent_error_a)))
+        print(("Model A sq_error,\t" + str(x_a) + ",\t" + str(0) + ",\t" + str(squared_error_a) + ",\t" + str(baseline_squared_error_a)))
+        print(("Model B %_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(percent_error_b) + ",\t" + str(baseline_percent_error_b)))
+        print(("Model B sq_error,\t" + str(x_b[0]) + ",\t" + str(x_b[1]) + ",\t" + str(squared_error_b) + ",\t" + str(baseline_squared_error_b)))
         print()
 
 if __name__ == "__main__":
diff --git a/media/libaom/src/tools/intersect-diffs.py b/media/libaom/src/tools/intersect-diffs.py
index df13c4ef70..87c4a6813e 100755
--- a/media/libaom/src/tools/intersect-diffs.py
+++ b/media/libaom/src/tools/intersect-diffs.py
@@ -16,6 +16,7 @@ in A and prints them to stdout. This is useful to determine the hunks in B that
 are relevant to A. The resulting file can be applied with patch(1) on top of A.
 """
 
+from __future__ import print_function
 __author__ = "jkoleszar@google.com"
 
 import sys
@@ -71,7 +72,7 @@ def main():
                 break
 
     if out_hunks:
-        print FormatDiffHunks(out_hunks)
+        print(FormatDiffHunks(out_hunks))
         sys.exit(1)
 
 if __name__ == "__main__":
diff --git a/media/libaom/src/tools/lint-hunks.py b/media/libaom/src/tools/lint-hunks.py
index d02bee16ce..18a7063b8c 100755
--- a/media/libaom/src/tools/lint-hunks.py
+++ b/media/libaom/src/tools/lint-hunks.py
@@ -10,6 +10,7 @@
 ## PATENTS file, you can obtain it at www.aomedia.org/license/patent.
 ##
 """Performs style checking on each diff hunk."""
+from __future__ import print_function
 import getopt
 import os
 import StringIO
@@ -65,17 +66,17 @@ def main(argv=None):
     try:
         try:
             opts, args = getopt.getopt(argv[1:], SHORT_OPTIONS, LONG_OPTIONS)
-        except getopt.error, msg:
+        except getopt.error as msg:
             raise Usage(msg)
 
         # process options
         for o, _ in opts:
             if o in ("-h", "--help"):
-                print __doc__
+                print(__doc__)
                 sys.exit(0)
 
         if args and len(args) > 1:
-            print __doc__
+            print(__doc__)
             sys.exit(0)
 
         # Find the fully qualified path to the root of the tree
@@ -105,7 +106,7 @@ def main(argv=None):
 
         # Run each affected file through cpplint
         lint_failed = False
-        for filename, affected_lines in file_affected_line_map.iteritems():
+        for filename, affected_lines in file_affected_line_map.items():
             if filename.split(".")[-1] not in ("c", "h", "cc"):
                 continue
 
@@ -129,17 +130,17 @@ def main(argv=None):
                     continue
                 warning_line_num = int(fields[1])
                 if warning_line_num in affected_lines:
-                    print "%s:%d:%s"%(filename, warning_line_num,
-                                      ":".join(fields[2:]))
+                    print("%s:%d:%s"%(filename, warning_line_num,
+                                      ":".join(fields[2:])))
                     lint_failed = True
 
         # Set exit code if any relevant lint errors seen
         if lint_failed:
             return 1
 
-    except Usage, err:
-        print >>sys.stderr, err
-        print >>sys.stderr, "for help use --help"
+    except Usage as err:
+        print(err, file=sys.stderr)
+        print("for help use --help", file=sys.stderr)
         return 2
 
 if __name__ == "__main__":
diff --git a/media/libjxl/src/doc/sphinx/conf.py b/media/libjxl/src/doc/sphinx/conf.py
index 1591aefc70..91ca1a621a 100644
--- a/media/libjxl/src/doc/sphinx/conf.py
+++ b/media/libjxl/src/doc/sphinx/conf.py
@@ -14,13 +14,13 @@ import subprocess
 def GetVersion():
     """Function to get the version of the current code."""
     with open(os.path.join(
-            os.path.dirname(__file__), '../../lib/CMakeLists.txt'), 'r') as f:
+            os.path.dirname(__file__), '../../lib/CMakeLists.txt')) as f:
         cmakevars = {}
         for line in f:
             m = re.match(r'set\(JPEGXL_([A-Z]+)_VERSION ([^\)]+)\)', line)
             if m:
                 cmakevars[m.group(1)] = m.group(2)
-    return '%s.%s.%s' % (cmakevars['MAJOR'], cmakevars['MINOR'], cmakevars['PATCH'])
+    return '{}.{}.{}'.format(cmakevars['MAJOR'], cmakevars['MINOR'], cmakevars['PATCH'])
 
 def ConfigProject(app, config):
     # Configure the doxygen xml directory as the "xml" directory next to the
diff --git a/media/libjxl/src/tools/benchmark/metrics/plots.py b/media/libjxl/src/tools/benchmark/metrics/plots.py
index 04b2bb24e5..323202f4ca 100755
--- a/media/libjxl/src/tools/benchmark/metrics/plots.py
+++ b/media/libjxl/src/tools/benchmark/metrics/plots.py
@@ -13,14 +13,14 @@ _, results, output_dir, *rest = sys.argv
 OUTPUT = rest[0] if rest else 'svg'
 # valid values: html, svg, png, webp, jpeg, pdf
 
-with open(results, 'r') as f:
+with open(results) as f:
     reader = csv.DictReader(f)
     all_results = list(reader)
 
-nonmetric_columns = set([
+nonmetric_columns = {
     "method", "image", "error", "size", "pixels", "enc_speed", "dec_speed",
     "bpp", "bppp", "qabpp"
-])
+}
 
 metrics = set(all_results[0].keys()) - nonmetric_columns
 
@@ -28,10 +28,10 @@ metrics = set(all_results[0].keys()) - nonmetric_columns
 def codec(method):
     sm = method.split(':')
     ssm = set(sm)
-    speeds = set([
+    speeds = {
         'kitten', 'falcon', 'wombat', 'cheetah', 'tortoise', 'squirrel',
         'hare', 'fast'
-    ])
+    }
     s = speeds.intersection(ssm)
     if sm[0] == 'custom':
         return sm[1]
@@ -205,10 +205,10 @@ def style(codec):
     return configs.get(codec, dict())
 
 
-visible_by_default = set([
+visible_by_default = {
     'jxl-kitten', 'ssim.444.aom.avif', 'heif', 'webp', 'jpeg', 'xt.jpg',
     'default.kdu.j2k'
-])
+}
 
 column_remap = {
     'p': '6-Butteraugli',
@@ -234,9 +234,9 @@ def remap(metric):
 
 
 for (m, img) in data:
-    fname = "%s/%s_%s" % (output_dir, m, img)
+    fname = "{}/{}_{}".format(output_dir, m, img)
     fig = go.Figure()
-    for method in sorted(data[(m, img)].keys(), key=pos):
+    for method in sorted(list(data[(m, img)].keys()), key=pos):
         vals = data[(m, img)][method]
         zvals = list(zip(*sorted(vals)))
         if not zvals:
diff --git a/media/libjxl/src/tools/conformance/conformance.py b/media/libjxl/src/tools/conformance/conformance.py
index 6f5ccb659f..7c31706e07 100755
--- a/media/libjxl/src/tools/conformance/conformance.py
+++ b/media/libjxl/src/tools/conformance/conformance.py
@@ -69,8 +69,8 @@ def CompareBinaries(ref_bin, dec_bin):
     return True
 
 
-TEST_KEYS = set(
-    ['reconstructed_jpeg', 'original_icc', 'rms_error', 'peak_error'])
+TEST_KEYS = {
+    'reconstructed_jpeg', 'original_icc', 'rms_error', 'peak_error'}
 
 
 def CheckMeta(dec, ref):
@@ -113,13 +113,13 @@ def ConformanceTestRunner(args):
         corpus_dir = os.path.dirname(args.corpus)
         corpus_txt = args.corpus
 
-    with open(corpus_txt, 'r') as f:
+    with open(corpus_txt) as f:
         for test_id in f:
             test_id = test_id.rstrip('\n')
             print(f"\033[94m\033[1mTesting {test_id}\033[0m", flush=True)
             test_dir = os.path.join(corpus_dir, test_id)
 
-            with open(os.path.join(test_dir, 'test.json'), 'r') as f:
+            with open(os.path.join(test_dir, 'test.json')) as f:
                 descriptor = json.load(f)
                 if 'sha256sums' in descriptor:
                     del descriptor['sha256sums']
@@ -176,7 +176,7 @@ def ConformanceTestRunner(args):
                     ok = ok & binary_ok
 
                 # Validate metadata.
-                with open(meta_filename, 'r') as f:
+                with open(meta_filename) as f:
                     meta = json.load(f)
 
                 ok = ok & CheckMeta(meta, descriptor)
diff --git a/media/libjxl/src/tools/conformance/generator.py b/media/libjxl/src/tools/conformance/generator.py
index e2a9b2e66a..36e5ba5237 100755
--- a/media/libjxl/src/tools/conformance/generator.py
+++ b/media/libjxl/src/tools/conformance/generator.py
@@ -49,7 +49,7 @@ def GenerateConformanceCorpus(args):
 
         test_dir = os.path.join(args.output, test_id)
         os.makedirs(test_dir, 0o755, exist_ok=True)
-        print('Generating %s' % (test_id, ))
+        print('Generating {}'.format(test_id))
         input_file = os.path.join(test_dir, 'input.jxl')
         shutil.copy(jxl, input_file)
 
@@ -69,7 +69,7 @@ def GenerateConformanceCorpus(args):
         # Decode and generate the reference files.
         subprocess.check_call(cmd)
 
-        with open(metadata_filename, 'r') as f:
+        with open(metadata_filename) as f:
             metadata = json.load(f)
 
         if os.path.exists(original_icc_filename):
diff --git a/media/libjxl/src/tools/optimizer/apply_simplex.py b/media/libjxl/src/tools/optimizer/apply_simplex.py
index 2f56766eba..6a6b50212d 100644
--- a/media/libjxl/src/tools/optimizer/apply_simplex.py
+++ b/media/libjxl/src/tools/optimizer/apply_simplex.py
@@ -34,7 +34,7 @@ import sys
 def ParseSimplex(fn):
     """Returns the simplex definition written by simplex_fork.py"""
 
-    with open(fn, "r") as f:
+    with open(fn) as f:
         line = f.readline()
         vec = eval(line)
     return vec
@@ -46,17 +46,17 @@ def PythonExpr(c_expr):
     def repl(m):
         return m.group(1)
 
-    return re.sub("(\d+)f", repl, c_expr)
+    return re.sub(r"(\d+)f", repl, c_expr)
 
 
 def UpdateSourceFile(fn, vec, keep_bias, id_min, id_max, minval):
     """Updates expressions containing a bias(N) term."""
 
-    with open(fn, "r") as f:
+    with open(fn) as f:
         lines_in = f.readlines()
         lines_out = []
-        rbias = "(bias\((\d+)\))"
-        r = " -?\d+\.\d+f?( (\+|-|\*) (\d+\.\d+f? \* )?" + rbias + ")"
+        rbias = r"(bias\((\d+)\))"
+        r = r" -?\d+\.\d+f?( (\+|-|\*) (\d+\.\d+f? \* )?" + rbias + ")"
         for line in lines_in:
             line_out = line
             x = re.search(r, line)
diff --git a/media/libjxl/src/tools/optimizer/simplex_fork.py b/media/libjxl/src/tools/optimizer/simplex_fork.py
index a63589d0ae..6978915357 100755
--- a/media/libjxl/src/tools/optimizer/simplex_fork.py
+++ b/media/libjxl/src/tools/optimizer/simplex_fork.py
@@ -16,10 +16,6 @@ https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method
 start as ./simplex_fork.py binary dimensions amount
 """
 
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-from six.moves import range
 import copy
 import os
 import random
diff --git a/media/libjxl/src/tools/optimizer/update_jpegli_global_scale.py b/media/libjxl/src/tools/optimizer/update_jpegli_global_scale.py
index 1a57c59db6..b1e9b20517 100644
--- a/media/libjxl/src/tools/optimizer/update_jpegli_global_scale.py
+++ b/media/libjxl/src/tools/optimizer/update_jpegli_global_scale.py
@@ -70,11 +70,11 @@ def EvalPnorm(build_dir, corpus_dir, codec):
   for line in out.splitlines():
     if line.startswith(codec):
       return float(line.split()[8])
-  raise Exception("Unexpected benchmark output:\n%sstderr:\n%s" % (out, err))
+  raise Exception("Unexpected benchmark output:\n{}stderr:\n{}".format(out, err))
 
 
 if len(sys.argv) != 3:
-  print("usage: ", sys.argv[0], "build-dir corpus-dir")
+  print(("usage: ", sys.argv[0], "build-dir corpus-dir"))
   exit(1)
 
 build_dir = sys.argv[1]
diff --git a/media/libjxl/src/tools/scripts/build_cleaner.py b/media/libjxl/src/tools/scripts/build_cleaner.py
index 7a357103d8..b55c318546 100644
--- a/media/libjxl/src/tools/scripts/build_cleaner.py
+++ b/media/libjxl/src/tools/scripts/build_cleaner.py
@@ -170,7 +170,7 @@ def MaybeUpdateFile(args, filename, new_text):
   otherwise it will return True when no changes were needed.
   """
   filepath = os.path.join(args.src_dir, filename)
-  with open(filepath, 'r') as f:
+  with open(filepath) as f:
     src_text = f.read()
 
   if new_text == src_text:
@@ -212,7 +212,7 @@ def FormatCMakeVar(name, var):
 
 
 def GetJpegLibVersion(src_dir):
-  with open(os.path.join(src_dir, 'CMakeLists.txt'), 'r') as f:
+  with open(os.path.join(src_dir, 'CMakeLists.txt')) as f:
     cmake_text = f.read()
     m = re.search(r'set\(JPEGLI_LIBJPEG_LIBRARY_SOVERSION "([0-9]+)"',
                   cmake_text)
@@ -229,7 +229,7 @@ def ToDocstringComment(lines):
 def BuildCleaner(args):
   repo_files = RepoFiles(args.src_dir)
 
-  with open(os.path.join(args.src_dir, 'lib/CMakeLists.txt'), 'r') as f:
+  with open(os.path.join(args.src_dir, 'lib/CMakeLists.txt')) as f:
     cmake_text = f.read()
   version = {'major_version': '', 'minor_version': '', 'patch_version': ''}
   for var in version.keys():
diff --git a/media/libjxl/src/tools/scripts/check_author.py b/media/libjxl/src/tools/scripts/check_author.py
index 7e16859335..074f00820f 100644
--- a/media/libjxl/src/tools/scripts/check_author.py
+++ b/media/libjxl/src/tools/scripts/check_author.py
@@ -20,7 +20,7 @@ def IsAuthorInFile(email, name, filename):
   # patterns.
   email_pattern_regex = re.compile(r'.*<([^>]+)>')
 
-  with open(filename, 'r') as f:
+  with open(filename) as f:
     for line in f:
       line = line.strip()
       if line.startswith('#') or not line:
@@ -31,7 +31,7 @@ def IsAuthorInFile(email, name, filename):
       # Exact email address match is OK, even if the name is different.
       if fnmatch.fnmatch(line, '* <%s>' % email):
         print(
-            "User %s <%s> matched with different name %s" % (name, email, line),
+            "User {} <{}> matched with different name {}".format(name, email, line),
             file=sys.stderr)
         return True
       # Organizations often have *@domain.com email patterns which don't match
@@ -39,14 +39,14 @@ def IsAuthorInFile(email, name, filename):
       if '*' in line:
         m = email_pattern_regex.match(line)
         if m and fnmatch.fnmatch(email, m.group(1)):
-          print("User %s <%s> matched pattern %s" % (name, email, line),
+          print("User {} <{}> matched pattern {}".format(name, email, line),
                 file=sys.stderr)
           return True
   return False
 
 def IndividualsInAlphabeticOrder(filename):
   """Checks if the names are in alphabetic order"""
-  with open(filename, 'r') as f:
+  with open(filename) as f:
     lines = f.readlines()
     individual_header = '# Individuals:\n'
     if individual_header in lines:
@@ -70,7 +70,7 @@ def CheckAuthor(args):
   author_in_file = IsAuthorInFile(
       args.email, args.name, authors_path)
   if not author_in_file:
-    print("User %s <%s> not found, please add yourself to the AUTHORS file" % (
+    print("User {} <{}> not found, please add yourself to the AUTHORS file".format(
               args.name, args.email),
           file=sys.stderr)
     print("Hint: to override author in PR run:\n"
diff --git a/media/libjxl/src/tools/scripts/demo_progressive_saliency_encoding.py b/media/libjxl/src/tools/scripts/demo_progressive_saliency_encoding.py
index 6eb5cadd54..b28ee23a1b 100644
--- a/media/libjxl/src/tools/scripts/demo_progressive_saliency_encoding.py
+++ b/media/libjxl/src/tools/scripts/demo_progressive_saliency_encoding.py
@@ -26,10 +26,6 @@ Method:
 
 """
 
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import print_function
-from six.moves import zip
 import ast  # For ast.literal_eval() only.
 import os
 import re
diff --git a/media/libjxl/src/tools/upscaling_coefficients/generate_upscaling_coefficients.py b/media/libjxl/src/tools/upscaling_coefficients/generate_upscaling_coefficients.py
index 17c404d1cd..31cdb83ca5 100755
--- a/media/libjxl/src/tools/upscaling_coefficients/generate_upscaling_coefficients.py
+++ b/media/libjxl/src/tools/upscaling_coefficients/generate_upscaling_coefficients.py
@@ -190,11 +190,11 @@ def weights_arrays(upscaling_factor, kernel_size=5):
   return (
       f"kernel[{upscaling_factor}][{upscaling_factor}][{kernel_size}][{kernel_size}]"
       f" = {{" + ", \n".join("{\n" + ", \n\n".join(
-          ("{" + ", \n".join("{" + ", ".join(
+          "{" + ", \n".join("{" + ", ".join(
               f"weights[{str(indices[kernel_size*i + j][kernel_size*a + b])}]"
               for b in range(kernel_size)) + "}"
                              for j in range(kernel_size)) + "}"
-           for a in range(upscaling_factor // 2))) + "\n}"
+           for a in range(upscaling_factor // 2)) + "\n}"
                              for i in range(upscaling_factor // 2)) + "}\n")
 
 
diff --git a/media/libopus/gen-sources.py b/media/libopus/gen-sources.py
index fdd0f556d2..7bbe9d56a6 100644
--- a/media/libopus/gen-sources.py
+++ b/media/libopus/gen-sources.py
@@ -34,7 +34,7 @@ def generate_sources_mozbuild(path):
             values = []
             definition_started = False
 
-            with open('%s/%s' % (path, makefile), 'r') as mk:
+            with open('{}/{}'.format(path, makefile)) as mk:
                 for line in mk:
                     line = line.rstrip()
                     result = var_definition.match(line)
diff --git a/media/libstagefright/files.py b/media/libstagefright/files.py
index 4d6775fa4b..16abe5c951 100644
--- a/media/libstagefright/files.py
+++ b/media/libstagefright/files.py
@@ -9,7 +9,7 @@ CXXFLAGS=[]
 CONFIG['_MSC_VER'] = 0
 CONFIG['OS_TARGET'] = 0
 
-class Exports(object):
+class Exports:
     def __init__(self):
         self.mp4_demuxer=[]
 
@@ -20,10 +20,10 @@ UNIFIED_SOURCES=[]
 LOCAL_INCLUDES=[]
 
 try:
-    execfile('moz.build')
+    exec(compile(open('moz.build', "rb").read(), 'moz.build', 'exec'))
 except:
     sys.exit(1)
 
 for f in SOURCES+UNIFIED_SOURCES:
     if not f.startswith('binding/'):
-        print f
+        print(f)
diff --git a/media/libvpx/libvpx/test/android/get_files.py b/media/libvpx/libvpx/test/android/get_files.py
index 98ce7b1947..539605ca25 100644
--- a/media/libvpx/libvpx/test/android/get_files.py
+++ b/media/libvpx/libvpx/test/android/get_files.py
@@ -11,6 +11,7 @@
 #   1) File / test_data folder does not exist
 #   2) SHA mismatch
 
+from __future__ import print_function
 import pycurl
 import csv
 import hashlib
diff --git a/media/libvpx/libvpx/test/android/scrape_gtest_log.py b/media/libvpx/libvpx/test/android/scrape_gtest_log.py
index 487845c270..2eafa156d6 100644
--- a/media/libvpx/libvpx/test/android/scrape_gtest_log.py
+++ b/media/libvpx/libvpx/test/android/scrape_gtest_log.py
@@ -13,6 +13,7 @@ waterfall to gather json results mixed in with gtest logs.  This is
 dubious software engineering.
 """
 
+from __future__ import print_function
 import getopt
 import json
 import os
@@ -22,7 +23,7 @@ import sys
 
 def main():
   if len(sys.argv) != 3:
-    print "Expects a file to write json to!"
+    print("Expects a file to write json to!")
     exit(1)
 
   try:
@@ -30,7 +31,7 @@ def main():
         getopt.getopt(sys.argv[1:], \
                       'o:', ['output-json='])
   except getopt.GetOptError:
-    print 'scrape_gtest_log.py -o <output_json>'
+    print('scrape_gtest_log.py -o <output_json>')
     sys.exit(2)
 
   output_json = ''
@@ -41,10 +42,10 @@ def main():
   blob = sys.stdin.read()
   json_string = '[' + ','.join('{' + x + '}' for x in
                                re.findall(r'{([^}]*.?)}', blob)) + ']'
-  print blob
+  print(blob)
 
   output = json.dumps(json.loads(json_string), indent=4, sort_keys=True)
-  print output
+  print(output)
 
   path = os.path.dirname(output_json)
   if path and not os.path.exists(path):
diff --git a/media/libvpx/libvpx/tools/cpplint.py b/media/libvpx/libvpx/tools/cpplint.py
index e3ebde2f5a..e3a97de303 100755
--- a/media/libvpx/libvpx/tools/cpplint.py
+++ b/media/libvpx/libvpx/tools/cpplint.py
@@ -512,7 +512,7 @@ _ALT_TOKEN_REPLACEMENT = {
 # False positives include C-style multi-line comments and multi-line strings
 # but those have always been troublesome for cpplint.
 _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
-    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+    r'[ =()](' + ('|'.join(list(_ALT_TOKEN_REPLACEMENT.keys()))) + r')(?=[ (]|$)')
 
 
 # These constants define types of headers for use with
diff --git a/media/libvpx/libvpx/tools/intersect-diffs.py b/media/libvpx/libvpx/tools/intersect-diffs.py
index 590e687b47..4317fa3f96 100755
--- a/media/libvpx/libvpx/tools/intersect-diffs.py
+++ b/media/libvpx/libvpx/tools/intersect-diffs.py
@@ -14,6 +14,7 @@ in A and prints them to stdout. This is useful to determine the hunks in B that
 are relevant to A. The resulting file can be applied with patch(1) on top of A.
 """
 
+from __future__ import print_function
 __author__ = "jkoleszar@google.com"
 
 import sys
diff --git a/media/libvpx/libvpx/tools/lint-hunks.py b/media/libvpx/libvpx/tools/lint-hunks.py
index 0a94afebb9..33f35d568f 100755
--- a/media/libvpx/libvpx/tools/lint-hunks.py
+++ b/media/libvpx/libvpx/tools/lint-hunks.py
@@ -8,6 +8,7 @@
 ##  be found in the AUTHORS file in the root of the source tree.
 ##
 """Performs style checking on each diff hunk."""
+from __future__ import print_function
 import getopt
 import os
 import io
diff --git a/media/libvpx/update.py b/media/libvpx/update.py
index 18d7166382..21b8c23a94 100755
--- a/media/libvpx/update.py
+++ b/media/libvpx/update.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import argparse
 import os
 import re
@@ -9,15 +10,15 @@ import shutil
 import sys
 import subprocess
 import tarfile
-import urllib
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 from pprint import pprint
 from StringIO import StringIO
 
 def prepare_upstream(prefix, commit=None):
     upstream_url = 'https://chromium.googlesource.com/webm/libvpx'
     shutil.rmtree(os.path.join(base, 'libvpx/'))
-    print(upstream_url + '/+archive/' + commit + '.tar.gz')
-    urllib.urlretrieve(upstream_url + '/+archive/' + commit + '.tar.gz', 'libvpx.tar.gz')
+    print((upstream_url + '/+archive/' + commit + '.tar.gz'))
+    six.moves.urllib.request.urlretrieve(upstream_url + '/+archive/' + commit + '.tar.gz', 'libvpx.tar.gz')
     tarfile.open('libvpx.tar.gz').extractall(path='libvpx')
     os.remove(os.path.join(base, 'libvpx.tar.gz'))
     os.chdir(base)
diff --git a/media/libyuv/tools_libyuv/autoroller/roll_deps.py b/media/libyuv/tools_libyuv/autoroller/roll_deps.py
index 5496e42403..2113e3cbe5 100755
--- a/media/libyuv/tools_libyuv/autoroller/roll_deps.py
+++ b/media/libyuv/tools_libyuv/autoroller/roll_deps.py
@@ -175,7 +175,7 @@ def ReadUrlContent(url):
   conn = urllib.request.urlopen(url)
   try:
     return conn.readlines()
-  except IOError as e:
+  except OSError as e:
     logging.exception('Error connecting to %s. Error: %s', url, e)
     raise
   finally:
@@ -277,7 +277,7 @@ def CalculateChangedClang(new_cr_rev):
         return match.group(1)
     raise RollError('Could not parse Clang revision from:\n' + '\n'.join('  ' + l for l in lines))
 
-  with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH, 'r') as f:
+  with open(CLANG_UPDATE_SCRIPT_LOCAL_PATH) as f:
     current_lines = f.readlines()
   current_rev = GetClangRev(current_lines)
 
@@ -291,10 +291,10 @@ def GenerateCommitMessage(current_cr_rev, new_cr_rev, current_commit_pos,
                           new_commit_pos, changed_deps_list, clang_change):
   current_cr_rev = current_cr_rev[0:10]
   new_cr_rev = new_cr_rev[0:10]
-  rev_interval = '%s..%s' % (current_cr_rev, new_cr_rev)
-  git_number_interval = '%s:%s' % (current_commit_pos, new_commit_pos)
+  rev_interval = '{}..{}'.format(current_cr_rev, new_cr_rev)
+  git_number_interval = '{}:{}'.format(current_commit_pos, new_commit_pos)
 
-  commit_msg = ['Roll chromium_revision %s (%s)\n' % (rev_interval,
+  commit_msg = ['Roll chromium_revision {} ({})\n'.format(rev_interval,
                                                     git_number_interval)]
   commit_msg.append('Change log: %s' % (CHROMIUM_LOG_TEMPLATE % rev_interval))
   commit_msg.append('Full diff: %s\n' % (CHROMIUM_COMMIT_TEMPLATE %
@@ -303,7 +303,7 @@ def GenerateCommitMessage(current_cr_rev, new_cr_rev, current_commit_pos,
     commit_msg.append('Changed dependencies:')
 
     for c in changed_deps_list:
-      commit_msg.append('* %s: %s/+log/%s..%s' % (c.path, c.url,
+      commit_msg.append('* {}: {}/+log/{}..{}'.format(c.path, c.url,
                                                   c.current_rev[0:10],
                                                   c.new_rev[0:10]))
     change_url = CHROMIUM_FILE_TEMPLATE % (rev_interval, 'DEPS')
@@ -350,7 +350,7 @@ def UpdateDepsFile(deps_filename, old_cr_revision, new_cr_revision,
           'target_os = ["android", "unix", "mac", "ios", "win"];\n'
           'Then run "gclient sync" again.' % local_dep_dir)
     _RunCommand(
-      ['gclient', 'setdep', '--revision', '%s@%s' % (dep.path, dep.new_rev)],
+      ['gclient', 'setdep', '--revision', '{}@{}'.format(dep.path, dep.new_rev)],
       working_dir=CHECKOUT_SRC_DIR)
 
 
diff --git a/media/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py b/media/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py
index af86bdd586..9acce41989 100755
--- a/media/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py
+++ b/media/libyuv/tools_libyuv/autoroller/unittests/roll_deps_test.py
@@ -55,11 +55,11 @@ class FakeCmd():
 
   def __call__(self, *args, **kwargs):
     if not self.expectations:
-      raise TestError('Got unexpected\n%s\n%s' % (args, kwargs))
+      raise TestError('Got unexpected\n{}\n{}'.format(args, kwargs))
     exp_args, exp_kwargs, exp_returns = self.expectations.pop(0)
     if args != exp_args or kwargs != exp_kwargs:
-      message = 'Expected:\n  args: %s\n  kwargs: %s\n' % (exp_args, exp_kwargs)
-      message += 'Got:\n  args: %s\n  kwargs: %s\n' % (args, kwargs)
+      message = 'Expected:\n  args: {}\n  kwargs: {}\n'.format(exp_args, exp_kwargs)
+      message += 'Got:\n  args: {}\n  kwargs: {}\n'.format(args, kwargs)
       raise TestError(message)
     return exp_returns
 
@@ -92,13 +92,13 @@ class TestRollChromiumRevision(unittest.TestCase):
 
     current_rev = TEST_DATA_VARS['chromium_revision']
     UpdateDepsFile(self._libyuv_depsfile, current_rev, new_rev, [])
-    with open(self._libyuv_depsfile, 'r') as deps_file:
+    with open(self._libyuv_depsfile) as deps_file:
       deps_contents = deps_file.read()
       self.assertTrue(new_rev in deps_contents,
-                      'Failed to find %s in\n%s' % (new_rev, deps_contents))
+                      'Failed to find {} in\n{}'.format(new_rev, deps_contents))
 
   def testParseDepsDict(self):
-    with open(self._libyuv_depsfile, 'r') as deps_file:
+    with open(self._libyuv_depsfile) as deps_file:
       deps_contents = deps_file.read()
     local_scope = ParseDepsDict(deps_contents)
     vars_dict = local_scope['vars']
diff --git a/media/mtransport/third_party/import.py b/media/mtransport/third_party/import.py
index 6defdf26b7..6a99a579e3 100644
--- a/media/mtransport/third_party/import.py
+++ b/media/mtransport/third_party/import.py
@@ -6,6 +6,7 @@
 # Execute as: /import.py <source-distribution> <target-dir>
 # <target-dir> must have 'IMPORT_FILES' in it
 
+from __future__ import print_function
 import sys
 import re
 import os
@@ -30,7 +31,7 @@ for l in f:
     FILES.append(l)
 
 for f in FILES:
-    print f
+    print(f)
     SOURCE_PATH = "%s/%s"%(DISTRO,f)
     DEST_PATH = "%s/%s"%(IMPORT_DIR,f)
     if not os.path.exists(SOURCE_PATH):
diff --git a/media/webrtc/trunk/build/android/adb_logcat_monitor.py b/media/webrtc/trunk/build/android/adb_logcat_monitor.py
index aeaef0b093..4f3cd258c5 100755
--- a/media/webrtc/trunk/build/android/adb_logcat_monitor.py
+++ b/media/webrtc/trunk/build/android/adb_logcat_monitor.py
@@ -16,6 +16,7 @@ resilient across phone disconnects and reconnects and start the logcat
 early enough to not miss anything.
 """
 
+from __future__ import print_function
 import logging
 import os
 import re
@@ -98,7 +99,7 @@ def main(base_dir, adb_cmd='adb'):
   """Monitor adb forever.  Expects a SIGINT (Ctrl-C) to kill."""
   # We create the directory to ensure 'run once' semantics
   if os.path.exists(base_dir):
-    print 'adb_logcat_monitor: %s already exists? Cleaning' % base_dir
+    print('adb_logcat_monitor: %s already exists? Cleaning' % base_dir)
     shutil.rmtree(base_dir, ignore_errors=True)
 
   os.makedirs(base_dir)
@@ -138,7 +139,7 @@ def main(base_dir, adb_cmd='adb'):
   except:
     logging.exception('Unexpected exception in main.')
   finally:
-    for process, _ in devices.itervalues():
+    for process, _ in devices.values():
       if process:
         try:
           process.terminate()
@@ -149,7 +150,7 @@ def main(base_dir, adb_cmd='adb'):
 
 if __name__ == '__main__':
   if 2 <= len(sys.argv) <= 3:
-    print 'adb_logcat_monitor: Initializing'
+    print('adb_logcat_monitor: Initializing')
     sys.exit(main(*sys.argv[1:3]))
 
-  print 'Usage: %s <base_dir> [<adb_binary_path>]' % sys.argv[0]
+  print('Usage: %s <base_dir> [<adb_binary_path>]' % sys.argv[0])
diff --git a/media/webrtc/trunk/build/android/adb_logcat_printer.py b/media/webrtc/trunk/build/android/adb_logcat_printer.py
index 5194668ec6..ea24b2aff8 100755
--- a/media/webrtc/trunk/build/android/adb_logcat_printer.py
+++ b/media/webrtc/trunk/build/android/adb_logcat_printer.py
@@ -18,6 +18,7 @@ will attempt to terminate the contained PID by sending a SIGINT and
 monitoring for the deletion of the aforementioned file.
 """
 
+from __future__ import print_function
 import cStringIO
 import logging
 import os
@@ -106,7 +107,7 @@ def GetDeviceLogs(log_filenames, logger):
   """
   device_logs = []
 
-  for device, device_files in log_filenames.iteritems():
+  for device, device_files in log_filenames.items():
     logger.debug('%s: %s', device, str(device_files))
     device_file_lines = []
     for cur_file in device_files:
@@ -197,6 +198,6 @@ def main(base_dir, output_file):
 
 if __name__ == '__main__':
   if len(sys.argv) == 1:
-    print 'Usage: %s <base_dir>' % sys.argv[0]
+    print('Usage: %s <base_dir>' % sys.argv[0])
     sys.exit(1)
   sys.exit(main(sys.argv[1], sys.stdout))
diff --git a/media/webrtc/trunk/build/android/device_stats_monitor.py b/media/webrtc/trunk/build/android/device_stats_monitor.py
index 181c3db5ff..cf3d41c9f9 100755
--- a/media/webrtc/trunk/build/android/device_stats_monitor.py
+++ b/media/webrtc/trunk/build/android/device_stats_monitor.py
@@ -10,6 +10,7 @@ Usage:
   ./device_stats_monitor.py --hz=20 --duration=5 --outfile=/tmp/foo
 """
 
+from __future__ import print_function
 import optparse
 import os
 import sys
@@ -34,10 +35,10 @@ def main(argv):
   monitor = device_stats_monitor.DeviceStatsMonitor(
       android_commands.AndroidCommands(), options.hz, options.build_type)
   monitor.Start()
-  print 'Waiting for %d seconds while profiling.' % options.duration
+  print('Waiting for %d seconds while profiling.' % options.duration)
   time.sleep(options.duration)
   url = monitor.StopAndCollect(options.outfile)
-  print 'View results in browser at %s' % url
+  print('View results in browser at %s' % url)
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
diff --git a/media/webrtc/trunk/build/android/device_status_check.py b/media/webrtc/trunk/build/android/device_status_check.py
index 3d695a2235..db8541f6b6 100755
--- a/media/webrtc/trunk/build/android/device_status_check.py
+++ b/media/webrtc/trunk/build/android/device_status_check.py
@@ -5,6 +5,7 @@
 # found in the LICENSE file.
 
 """A class to keep track of devices across builds and report state."""
+from __future__ import print_function
 import logging
 import optparse
 import os
@@ -112,7 +113,7 @@ def CheckForMissingDevices(options, adb_online_devs):
          'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
          'adb devices(GetAttachedDevices): %s' % GetAttachedDevices()])
 
-    print body
+    print(body)
 
     # Only send email if the first time a particular device goes offline
     last_missing = ReadDeviceList('.last_missing')
@@ -129,15 +130,15 @@ def CheckForMissingDevices(options, adb_online_devs):
         server.sendmail(from_address, [to_address], msg_body)
         server.quit()
       except Exception as e:
-        print 'Failed to send alert email. Error: %s' % e
+        print('Failed to send alert email. Error: %s' % e)
   else:
     new_devs = set(adb_online_devs) - set(last_devices)
     if new_devs and os.path.exists(last_devices_path):
       buildbot_report.PrintWarning()
       buildbot_report.PrintSummaryText(
           '%d new devices detected' % len(new_devs))
-      print ('New devices detected %s. And now back to your '
-             'regularly scheduled program.' % list(new_devs))
+      print(('New devices detected %s. And now back to your '
+             'regularly scheduled program.' % list(new_devs)))
   WriteDeviceList('.last_devices', (adb_online_devs + last_devices))
   WriteDeviceList('.last_missing', missing_devs)
 
@@ -156,14 +157,14 @@ def main():
   devices = GetAttachedDevices()
   types, builds, reports = [], [], []
   if devices:
-    types, builds, reports = zip(*[DeviceInfo(dev) for dev in devices])
+    types, builds, reports = list(zip(*[DeviceInfo(dev) for dev in devices]))
 
   unique_types = list(set(types))
   unique_builds = list(set(builds))
 
   buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s'
                            % (len(devices), unique_types, unique_builds))
-  print '\n'.join(reports)
+  print('\n'.join(reports))
   CheckForMissingDevices(options, devices)
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/build/android/emulator.py b/media/webrtc/trunk/build/android/emulator.py
index 77c9a75daa..d27c424495 100755
--- a/media/webrtc/trunk/build/android/emulator.py
+++ b/media/webrtc/trunk/build/android/emulator.py
@@ -82,7 +82,7 @@ class PortPool(object):
     a killed emulator "hangs on" to a port long enough to prevent
     relaunch.  This is especially true on slow machines (like a bot).
     Cycling through a port start position helps make us resilient."""
-    ports = range(cls._port_min, cls._port_max, 2)
+    ports = list(range(cls._port_min, cls._port_max, 2))
     n = cls._port_current_index
     cls._port_current_index = (n + 1) % len(ports)
     return ports[n:] + ports[:n]
diff --git a/media/webrtc/trunk/build/android/lighttpd_server.py b/media/webrtc/trunk/build/android/lighttpd_server.py
index 11ae794d4a..a0936507db 100755
--- a/media/webrtc/trunk/build/android/lighttpd_server.py
+++ b/media/webrtc/trunk/build/android/lighttpd_server.py
@@ -10,9 +10,10 @@ Usage:
   lighttpd_server PATH_TO_DOC_ROOT
 """
 
+from __future__ import print_function
 import codecs
 import contextlib
-import httplib
+import six.moves.http_client
 import os
 import random
 import shutil
@@ -103,8 +104,8 @@ class LighttpdServer(object):
       self.process.close()
 
       if self.fixed_port or not 'in use' in server_error:
-        print 'Client error:', client_error
-        print 'Server error:', server_error
+        print('Client error:', client_error)
+        print('Server error:', server_error)
         return False
       self.port = self._GetRandomPort()
     return True
@@ -118,10 +119,10 @@ class LighttpdServer(object):
   def _TestServerConnection(self):
     # Wait for server to start
     server_msg = ''
-    for timeout in xrange(1, 5):
+    for timeout in range(1, 5):
       client_error = None
       try:
-        with contextlib.closing(httplib.HTTPConnection(
+        with contextlib.closing(six.moves.http_client.HTTPConnection(
             '127.0.0.1', self.port, timeout=timeout)) as http:
           http.set_debuglevel(timeout > 3)
           http.request('HEAD', '/')
@@ -133,7 +134,7 @@ class LighttpdServer(object):
           client_error = ('Bad response: %s %s version %s\n  ' %
                           (r.status, r.reason, r.version) +
                           '\n  '.join([': '.join(h) for h in r.getheaders()]))
-      except (httplib.HTTPException, socket.error) as client_error:
+      except (six.moves.http_client.HTTPException, socket.error) as client_error:
         pass  # Probably too quick connecting: try again
       # Check for server startup error messages
       ix = self.process.expect([pexpect.TIMEOUT, pexpect.EOF, '.+'],
@@ -241,10 +242,10 @@ def main(argv):
   server = LighttpdServer(*argv[1:])
   try:
     if server.StartupHttpServer():
-      raw_input('Server running at http://127.0.0.1:%s -'
+      input('Server running at http://127.0.0.1:%s -'
                 ' press Enter to exit it.' % server.port)
     else:
-      print 'Server exit code:', server.process.exitstatus
+      print('Server exit code:', server.process.exitstatus)
   finally:
     server.ShutdownHttpServer()
 
diff --git a/media/webrtc/trunk/build/android/pylib/android_commands.py b/media/webrtc/trunk/build/android/pylib/android_commands.py
index 8a1562caad..f5d100050a 100644
--- a/media/webrtc/trunk/build/android/pylib/android_commands.py
+++ b/media/webrtc/trunk/build/android/pylib/android_commands.py
@@ -7,6 +7,7 @@
 Assumes adb binary is currently on system path.
 """
 
+from __future__ import print_function
 import collections
 import datetime
 import logging
@@ -18,7 +19,7 @@ import sys
 import tempfile
 import time
 
-import io_stats_parser
+from . import io_stats_parser
 from pylib import pexpect
 
 CHROME_SRC = os.path.join(
@@ -27,7 +28,7 @@ CHROME_SRC = os.path.join(
 sys.path.append(os.path.join(CHROME_SRC, 'third_party', 'android_testrunner'))
 import adb_interface
 
-import cmd_helper
+from . import cmd_helper
 import errors  #  is under ../../../third_party/android_testrunner/errors.py
 
 
@@ -347,7 +348,7 @@ class AndroidCommands(object):
         if 'Success' in install_status:
           return install_status
       except errors.WaitForResponseTimedOutError:
-        print '@@@STEP_WARNINGS@@@'
+        print('@@@STEP_WARNINGS@@@')
         logging.info('Timeout on installing %s' % apk_path)
 
       if reboots_left <= 0:
@@ -587,7 +588,7 @@ class AndroidCommands(object):
       if not os.path.exists(md5sum_path):
         md5sum_path = '%s/out/Release/md5sum_bin' % (CHROME_SRC)
         if not os.path.exists(md5sum_path):
-          print >> sys.stderr, 'Please build md5sum.'
+          print('Please build md5sum.', file=sys.stderr)
           sys.exit(1)
       command = 'push %s %s' % (md5sum_path, MD5SUM_DEVICE_PATH)
       assert _HasAdbPushSucceeded(self._adb.SendCommand(command))
@@ -671,7 +672,7 @@ class AndroidCommands(object):
     temp_props_file = tempfile.NamedTemporaryFile()
     properties = ''
     if self._adb.Pull(LOCAL_PROPERTIES_PATH, temp_props_file.name):
-      properties = file(temp_props_file.name).read()
+      properties = open(temp_props_file.name).read()
     re_search = re.compile(r'^\s*' + re.escape(JAVA_ASSERT_PROPERTY) +
                            r'\s*=\s*all\s*$', re.MULTILINE)
     if enable != bool(re.search(re_search, properties)):
@@ -681,7 +682,7 @@ class AndroidCommands(object):
       if enable:
         properties += '\n%s=all\n' % JAVA_ASSERT_PROPERTY
 
-      file(temp_props_file.name, 'w').write(properties)
+      open(temp_props_file.name, 'w').write(properties)
       self._adb.Push(temp_props_file.name, LOCAL_PROPERTIES_PATH)
 
     # Next, check the current runtime value is what we need, and
diff --git a/media/webrtc/trunk/build/android/pylib/apk_info.py b/media/webrtc/trunk/build/android/pylib/apk_info.py
index 7e8867570b..bfdbc5e73f 100644
--- a/media/webrtc/trunk/build/android/pylib/apk_info.py
+++ b/media/webrtc/trunk/build/android/pylib/apk_info.py
@@ -8,7 +8,7 @@ import collections
 import os
 import re
 
-import cmd_helper
+from . import cmd_helper
 
 
 class ApkInfo(object):
@@ -129,7 +129,7 @@ class ApkInfo(object):
 
   def GetAnnotatedTests(self, annotation_filter_list):
     """Returns a list of all tests that match the given annotation filters."""
-    return [test for test, annotations in self._GetAnnotationMap().iteritems()
+    return [test for test, annotations in self._GetAnnotationMap(.items())
             if self._IsTestMethod(test) and self._AnnotationsMatchFilters(
                 annotation_filter_list, annotations)]
 
diff --git a/media/webrtc/trunk/build/android/pylib/base_test_runner.py b/media/webrtc/trunk/build/android/pylib/base_test_runner.py
index 619bc6edf0..10ed5f0904 100644
--- a/media/webrtc/trunk/build/android/pylib/base_test_runner.py
+++ b/media/webrtc/trunk/build/android/pylib/base_test_runner.py
@@ -3,21 +3,21 @@
 # found in the LICENSE file.
 
 import contextlib
-import httplib
+import six.moves.http_client
 import logging
 import os
 import tempfile
 import time
 
-import android_commands
-import constants
-from chrome_test_server_spawner import SpawningServer
-import constants
-from flag_changer import FlagChanger
-from forwarder import Forwarder
+from . import android_commands
+from . import constants
+from .chrome_test_server_spawner import SpawningServer
+from . import constants
+from .flag_changer import FlagChanger
+from .forwarder import Forwarder
 import lighttpd_server
-import ports
-from valgrind_tools import CreateTool
+from . import ports
+from .valgrind_tools import CreateTool
 
 
 # A file on device to store ports of net test server. The format of the file is
@@ -181,7 +181,7 @@ class BaseTestRunner(object):
     server_ready = False
     error_msgs = []
     # Try 3 times to launch test spawner server.
-    for i in xrange(0, 3):
+    for i in range(0, 3):
       # Do not allocate port for test server here. We will allocate
       # different port for individual test in TestServerThread.
       self.test_server_spawner_port = ports.AllocateTestServerPort()
diff --git a/media/webrtc/trunk/build/android/pylib/base_test_sharder.py b/media/webrtc/trunk/build/android/pylib/base_test_sharder.py
index 48206c202c..a818c1f753 100644
--- a/media/webrtc/trunk/build/android/pylib/base_test_sharder.py
+++ b/media/webrtc/trunk/build/android/pylib/base_test_sharder.py
@@ -6,7 +6,7 @@
 import logging
 import multiprocessing
 
-from test_result import TestResults
+from .test_result import TestResults
 
 
 def _ShardedTestRunnable(test):
@@ -78,7 +78,7 @@ class BaseTestSharder(object):
     logging.warning('Look for the "Final result" banner in the end.')
     logging.warning('*' * 80)
     final_results = TestResults()
-    for retry in xrange(self.retries):
+    for retry in range(self.retries):
       logging.warning('Try %d of %d', retry + 1, self.retries)
       self.SetupSharding(self.tests)
       test_runners = []
diff --git a/media/webrtc/trunk/build/android/pylib/buildbot_report.py b/media/webrtc/trunk/build/android/pylib/buildbot_report.py
index fe3fcd638e..dc68171b29 100644
--- a/media/webrtc/trunk/build/android/pylib/buildbot_report.py
+++ b/media/webrtc/trunk/build/android/pylib/buildbot_report.py
@@ -4,6 +4,7 @@
 
 """Helper functions to print buildbot messages."""
 
+from __future__ import print_function
 def PrintLink(label, url):
   """Adds a link with name |label| linking to |url| to current buildbot step.
 
@@ -11,7 +12,7 @@ def PrintLink(label, url):
     label: A string with the name of the label.
     url: A string of the URL.
   """
-  print '@@@STEP_LINK@%s@%s@@@' % (label, url)
+  print('@@@STEP_LINK@%s@%s@@@' % (label, url))
 
 
 def PrintMsg(msg):
@@ -20,7 +21,7 @@ def PrintMsg(msg):
   Args:
     msg: String to be appended.
   """
-  print '@@@STEP_TEXT@%s@@@' % msg
+  print('@@@STEP_TEXT@%s@@@' % msg)
 
 
 def PrintSummaryText(msg):
@@ -29,18 +30,18 @@ def PrintSummaryText(msg):
   Args:
     msg: String to be appended.
   """
-  print '@@@STEP_SUMMARY_TEXT@%s@@@' % msg
+  print('@@@STEP_SUMMARY_TEXT@%s@@@' % msg)
 
 
 def PrintError():
   """Marks the current step as failed."""
-  print '@@@STEP_FAILURE@@@'
+  print('@@@STEP_FAILURE@@@')
 
 
 def PrintWarning():
   """Marks the current step with a warning."""
-  print '@@@STEP_WARNINGS@@@'
+  print('@@@STEP_WARNINGS@@@')
 
 
 def PrintNamedStep(step):
-  print '@@@BUILD_STEP %s@@@' % step
+  print('@@@BUILD_STEP %s@@@' % step)
diff --git a/media/webrtc/trunk/build/android/pylib/chrome_test_server_spawner.py b/media/webrtc/trunk/build/android/pylib/chrome_test_server_spawner.py
index 512a6091db..e46acf4d88 100644
--- a/media/webrtc/trunk/build/android/pylib/chrome_test_server_spawner.py
+++ b/media/webrtc/trunk/build/android/pylib/chrome_test_server_spawner.py
@@ -8,7 +8,7 @@ It's used to accept requests from the device to spawn and kill instances of the
 chrome test server on the host.
 """
 
-import BaseHTTPServer
+import six.moves.BaseHTTPServer
 import json
 import logging
 import os
@@ -17,11 +17,11 @@ import struct
 import subprocess
 import threading
 import time
-import urlparse
+import six.moves.urllib.parse
 
-import constants
-from forwarder import Forwarder
-import ports
+from . import constants
+from .forwarder import Forwarder
+from . import ports
 
 
 # Path that are needed to import necessary modules when running testserver.py.
@@ -147,7 +147,7 @@ class TestServerThread(threading.Thread):
       return False
     logging.info('Got port json data: %s', port_json)
     port_json = json.loads(port_json)
-    if port_json.has_key('port') and isinstance(port_json['port'], int):
+    if 'port' in port_json and isinstance(port_json['port'], int):
       self.host_port = port_json['port']
       return _CheckPortStatus(self.host_port, True)
     logging.error('Failed to get port information from the server data.')
@@ -177,29 +177,29 @@ class TestServerThread(threading.Thread):
       data_dir = os.path.join(constants.CHROME_DIR, data_dir)
     self.command_line.append('--data-dir=%s' % data_dir)
     # The following arguments are optional depending on the individual test.
-    if self.arguments.has_key('log-to-console'):
+    if 'log-to-console' in self.arguments:
       self.command_line.append('--log-to-console')
-    if self.arguments.has_key('auth-token'):
+    if 'auth-token' in self.arguments:
       self.command_line.append('--auth-token=%s' % self.arguments['auth-token'])
-    if self.arguments.has_key('https'):
+    if 'https' in self.arguments:
       self.command_line.append('--https')
-      if self.arguments.has_key('cert-and-key-file'):
+      if 'cert-and-key-file' in self.arguments:
         self.command_line.append('--cert-and-key-file=%s' % os.path.join(
             constants.CHROME_DIR, self.arguments['cert-and-key-file']))
-      if self.arguments.has_key('ocsp'):
+      if 'ocsp' in self.arguments:
         self.command_line.append('--ocsp=%s' % self.arguments['ocsp'])
-      if self.arguments.has_key('https-record-resume'):
+      if 'https-record-resume' in self.arguments:
         self.command_line.append('--https-record-resume')
-      if self.arguments.has_key('ssl-client-auth'):
+      if 'ssl-client-auth' in self.arguments:
         self.command_line.append('--ssl-client-auth')
-      if self.arguments.has_key('tls-intolerant'):
+      if 'tls-intolerant' in self.arguments:
         self.command_line.append('--tls-intolerant=%s' %
                                  self.arguments['tls-intolerant'])
-      if self.arguments.has_key('ssl-client-ca'):
+      if 'ssl-client-ca' in self.arguments:
         for ca in self.arguments['ssl-client-ca']:
           self.command_line.append('--ssl-client-ca=%s' %
                                    os.path.join(constants.CHROME_DIR, ca))
-      if self.arguments.has_key('ssl-bulk-cipher'):
+      if 'ssl-bulk-cipher' in self.arguments:
         for bulk_cipher in self.arguments['ssl-bulk-cipher']:
           self.command_line.append('--ssl-bulk-cipher=%s' % bulk_cipher)
 
@@ -261,7 +261,7 @@ class TestServerThread(threading.Thread):
     self.wait_event.wait()
 
 
-class SpawningServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+class SpawningServerRequestHandler(six.moves.BaseHTTPServer.BaseHTTPRequestHandler):
   """A handler used to process http GET/POST request."""
 
   def _SendResponse(self, response_code, response_reason, additional_headers,
@@ -344,7 +344,7 @@ class SpawningServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     self.server.test_server_instance = None
 
   def do_POST(self):
-    parsed_path = urlparse.urlparse(self.path)
+    parsed_path = six.moves.urllib.parse.urlparse(self.path)
     action = parsed_path.path
     logging.info('Action for POST method is: %s.', action)
     if action == '/start':
@@ -354,9 +354,9 @@ class SpawningServerRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
       logging.info('Encounter unknown request: %s.', action)
 
   def do_GET(self):
-    parsed_path = urlparse.urlparse(self.path)
+    parsed_path = six.moves.urllib.parse.urlparse(self.path)
     action = parsed_path.path
-    params = urlparse.parse_qs(parsed_path.query, keep_blank_values=1)
+    params = six.moves.urllib.parse.parse_qs(parsed_path.query, keep_blank_values=1)
     logging.info('Action for GET method is: %s.', action)
     for param in params:
       logging.info('%s=%s', param, params[param][0])
@@ -378,7 +378,7 @@ class SpawningServer(object):
 
   def __init__(self, test_server_spawner_port, adb, tool, build_type):
     logging.info('Creating new spawner on port: %d.', test_server_spawner_port)
-    self.server = BaseHTTPServer.HTTPServer(('', test_server_spawner_port),
+    self.server = six.moves.BaseHTTPServer.HTTPServer(('', test_server_spawner_port),
                                             SpawningServerRequestHandler)
     self.port = test_server_spawner_port
     self.server.adb = adb
diff --git a/media/webrtc/trunk/build/android/pylib/debug_info.py b/media/webrtc/trunk/build/android/pylib/debug_info.py
index 6f0f55a33f..856087f7dd 100644
--- a/media/webrtc/trunk/build/android/pylib/debug_info.py
+++ b/media/webrtc/trunk/build/android/pylib/debug_info.py
@@ -13,7 +13,7 @@ import string
 import subprocess
 import tempfile
 
-import cmd_helper
+from . import cmd_helper
 
 
 TOMBSTONE_DIR = '/data/tombstones/'
diff --git a/media/webrtc/trunk/build/android/pylib/device_stats_monitor.py b/media/webrtc/trunk/build/android/pylib/device_stats_monitor.py
index 8be4efae59..bb6700f8a6 100644
--- a/media/webrtc/trunk/build/android/pylib/device_stats_monitor.py
+++ b/media/webrtc/trunk/build/android/pylib/device_stats_monitor.py
@@ -9,10 +9,10 @@ import json
 import os
 import subprocess
 import sys
-import urllib
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 
-import constants
-import io_stats_parser
+from . import constants
+from . import io_stats_parser
 
 
 class DeviceStatsMonitor(object):
@@ -95,7 +95,7 @@ class DeviceStatsMonitor(object):
     with open(output_path, 'w') as f:
       f.write('display(%d, %s, %s);' % (self._hz, json.dumps(results), units))
     return 'file://%s?results=file://%s' % (
-        DeviceStatsMonitor.RESULT_VIEWER_PATH, urllib.quote(output_path))
+        DeviceStatsMonitor.RESULT_VIEWER_PATH, six.moves.urllib.parse.quote(output_path))
 
 
   @staticmethod
diff --git a/media/webrtc/trunk/build/android/pylib/fake_dns.py b/media/webrtc/trunk/build/android/pylib/fake_dns.py
index 1c64490045..df9afb8e99 100644
--- a/media/webrtc/trunk/build/android/pylib/fake_dns.py
+++ b/media/webrtc/trunk/build/android/pylib/fake_dns.py
@@ -2,8 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import android_commands
-import constants
+from . import android_commands
+from . import constants
 import logging
 import os
 import subprocess
diff --git a/media/webrtc/trunk/build/android/pylib/flag_changer.py b/media/webrtc/trunk/build/android/pylib/flag_changer.py
index 6210561568..1fd425fedf 100644
--- a/media/webrtc/trunk/build/android/pylib/flag_changer.py
+++ b/media/webrtc/trunk/build/android/pylib/flag_changer.py
@@ -2,7 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import constants
+from __future__ import print_function
+from . import constants
 import traceback
 import warnings
 
@@ -86,7 +87,7 @@ class FlagChanger(object):
 
   def _UpdateCommandLineFile(self):
     """Writes out the command line to the file, or removes it if empty."""
-    print "Current flags: ", self._current_flags
+    print("Current flags: ", self._current_flags)
 
     if self._current_flags:
       self._android_cmd.SetFileContents(CHROME_COMMAND_FILE,
diff --git a/media/webrtc/trunk/build/android/pylib/forwarder.py b/media/webrtc/trunk/build/android/pylib/forwarder.py
index bc41db3ff3..d271fb464d 100644
--- a/media/webrtc/trunk/build/android/pylib/forwarder.py
+++ b/media/webrtc/trunk/build/android/pylib/forwarder.py
@@ -8,10 +8,10 @@ import re
 import sys
 import time
 
-import android_commands
-import cmd_helper
-import constants
-import ports
+from . import android_commands
+from . import cmd_helper
+from . import constants
+from . import ports
 
 from pylib import pexpect
 
diff --git a/media/webrtc/trunk/build/android/pylib/java_unittest_utils.py b/media/webrtc/trunk/build/android/pylib/java_unittest_utils.py
index b5446dcf95..e11aa879fe 100644
--- a/media/webrtc/trunk/build/android/pylib/java_unittest_utils.py
+++ b/media/webrtc/trunk/build/android/pylib/java_unittest_utils.py
@@ -6,8 +6,8 @@
 
 import os
 
-import android_commands
-from run_java_tests import TestRunner
+from . import android_commands
+from .run_java_tests import TestRunner
 
 
 def _GetPackageName(fname):
diff --git a/media/webrtc/trunk/build/android/pylib/json_perf_parser.py b/media/webrtc/trunk/build/android/pylib/json_perf_parser.py
index 1a8e617539..7e105877f0 100644
--- a/media/webrtc/trunk/build/android/pylib/json_perf_parser.py
+++ b/media/webrtc/trunk/build/android/pylib/json_perf_parser.py
@@ -65,7 +65,7 @@ def GetAverageRunInfo(json_data, name):
 
   def EntryFilter(entry):
     return entry['cat'] == 'Java' and entry['name'] == name
-  filtered_entries = filter(EntryFilter, json_data)
+  filtered_entries = list(filter(EntryFilter, json_data))
 
   result = {}
 
diff --git a/media/webrtc/trunk/build/android/pylib/perf_tests_helper.py b/media/webrtc/trunk/build/android/pylib/perf_tests_helper.py
index c0a3ee413d..e642ba16ff 100644
--- a/media/webrtc/trunk/build/android/pylib/perf_tests_helper.py
+++ b/media/webrtc/trunk/build/android/pylib/perf_tests_helper.py
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 import re
 
-import android_commands
+from . import android_commands
 import math
 
 # Valid values of result type.
@@ -75,7 +76,7 @@ def PrintPerfResult(measurement, trace, values, units, result_type='default',
   if sd:
     output += '\nSd  %s: %f%s' % (measurement, sd, units)
   if print_to_stdout:
-    print output
+    print(output)
   return output
 
 
diff --git a/media/webrtc/trunk/build/android/pylib/ports.py b/media/webrtc/trunk/build/android/pylib/ports.py
index e9b6b901e0..1284c924ba 100644
--- a/media/webrtc/trunk/build/android/pylib/ports.py
+++ b/media/webrtc/trunk/build/android/pylib/ports.py
@@ -6,15 +6,15 @@
 
 import contextlib
 import fcntl
-import httplib
+import six.moves.http_client
 import logging
 import os
 import re
 import socket
 import traceback
 
-import cmd_helper
-import constants
+from . import cmd_helper
+from . import constants
 
 
 #The following two methods are used to allocate the port source for various
@@ -143,10 +143,10 @@ def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/',
     message the server returns when connect status is false.
   """
   assert tries >= 1
-  for i in xrange(0, tries):
+  for i in range(0, tries):
     client_error = None
     try:
-      with contextlib.closing(httplib.HTTPConnection(
+      with contextlib.closing(six.moves.http_client.HTTPConnection(
           host, port, timeout=timeout)) as http:
         # Output some debug information when we have tried more than 2 times.
         http.set_debuglevel(i >= 2)
@@ -158,7 +158,7 @@ def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/',
         client_error = ('Bad response: %s %s version %s\n  ' %
                         (r.status, r.reason, r.version) +
                         '\n  '.join([': '.join(h) for h in r.getheaders()]))
-    except (httplib.HTTPException, socket.error) as e:
+    except (six.moves.http_client.HTTPException, socket.error) as e:
       # Probably too quick connecting: try again.
       exception_error_msgs = traceback.format_exception_only(type(e), e)
       if exception_error_msgs:
diff --git a/media/webrtc/trunk/build/android/pylib/python_test_base.py b/media/webrtc/trunk/build/android/pylib/python_test_base.py
index 3517cdda83..3546fe98d4 100644
--- a/media/webrtc/trunk/build/android/pylib/python_test_base.py
+++ b/media/webrtc/trunk/build/android/pylib/python_test_base.py
@@ -23,10 +23,10 @@ import logging
 import os
 import time
 
-import android_commands
-import apk_info
-from run_java_tests import TestRunner
-from test_result import SingleTestResult, TestResults
+from . import android_commands
+from . import apk_info
+from .run_java_tests import TestRunner
+from .test_result import SingleTestResult, TestResults
 
 
 # aka the parent of com.google.android
diff --git a/media/webrtc/trunk/build/android/pylib/python_test_caller.py b/media/webrtc/trunk/build/android/pylib/python_test_caller.py
index 882b892997..d1da3a2f2a 100644
--- a/media/webrtc/trunk/build/android/pylib/python_test_caller.py
+++ b/media/webrtc/trunk/build/android/pylib/python_test_caller.py
@@ -9,7 +9,7 @@ import logging
 import sys
 import time
 
-from test_result import TestResults
+from .test_result import TestResults
 
 
 def CallPythonTest(test, options):
diff --git a/media/webrtc/trunk/build/android/pylib/python_test_sharder.py b/media/webrtc/trunk/build/android/pylib/python_test_sharder.py
index e27096d788..eca12de54d 100644
--- a/media/webrtc/trunk/build/android/pylib/python_test_sharder.py
+++ b/media/webrtc/trunk/build/android/pylib/python_test_sharder.py
@@ -8,10 +8,10 @@ import copy
 import logging
 import multiprocessing
 
-from python_test_caller import CallPythonTest
-from run_java_tests import FatalTestException
-import sharded_tests_queue
-from test_result import TestResults
+from .python_test_caller import CallPythonTest
+from .run_java_tests import FatalTestException
+from . import sharded_tests_queue
+from .test_result import TestResults
 
 
 def SetTestsContainer(tests_container):
@@ -123,7 +123,7 @@ class PythonTestSharder(object):
     all_passed = []
     test_results = TestResults()
     tests_to_run = self.tests
-    for retry in xrange(self.retries):
+    for retry in range(self.retries):
       logging.warning('Try %d of %d', retry + 1, self.retries)
       self._SetupSharding(self.tests)
       test_runners = self._MakeTestRunners(self.attached_devices)
@@ -197,7 +197,7 @@ class PythonTestSharder(object):
       A list of test objects which correspond to test names found in
       failed_tests, or an empty list if there is no correspondence.
     """
-    failed_test_names = map(lambda t: t.test_name, failed_tests)
+    failed_test_names = [t.test_name for t in failed_tests]
     tests_to_retry = [t for t in available_tests
                       if t.qualified_name in failed_test_names]
     return tests_to_retry
diff --git a/media/webrtc/trunk/build/android/pylib/run_java_tests.py b/media/webrtc/trunk/build/android/pylib/run_java_tests.py
index fc0a13fd81..77e01858bd 100644
--- a/media/webrtc/trunk/build/android/pylib/run_java_tests.py
+++ b/media/webrtc/trunk/build/android/pylib/run_java_tests.py
@@ -12,19 +12,19 @@ import shutil
 import sys
 import time
 
-import android_commands
-import apk_info
-from base_test_runner import BaseTestRunner
-from base_test_sharder import BaseTestSharder, SetTestsContainer
-import cmd_helper
-import constants
+from . import android_commands
+from . import apk_info
+from .base_test_runner import BaseTestRunner
+from .base_test_sharder import BaseTestSharder, SetTestsContainer
+from . import cmd_helper
+from . import constants
 import errors
-from forwarder import Forwarder
-from json_perf_parser import GetAverageRunInfoFromJSONString
-from perf_tests_helper import PrintPerfResult
-import sharded_tests_queue
-from test_result import SingleTestResult, TestResults
-import valgrind_tools
+from .forwarder import Forwarder
+from .json_perf_parser import GetAverageRunInfoFromJSONString
+from .perf_tests_helper import PrintPerfResult
+from . import sharded_tests_queue
+from .test_result import SingleTestResult, TestResults
+from . import valgrind_tools
 
 _PERF_TEST_ANNOTATION = 'PerfTest'
 
@@ -477,7 +477,7 @@ class TestRunner(BaseTestRunner):
       # See ../../third_party/android/testrunner/adb_interface.py
       except (errors.WaitForResponseTimedOutError,
               errors.DeviceUnresponsiveError,
-              errors.InstrumentationError), e:
+              errors.InstrumentationError) as e:
         if start_date_ms:
           duration_ms = int(time.time()) * 1000 - start_date_ms
         else:
diff --git a/media/webrtc/trunk/build/android/pylib/run_python_tests.py b/media/webrtc/trunk/build/android/pylib/run_python_tests.py
index 7d39f48295..f628c02ea3 100644
--- a/media/webrtc/trunk/build/android/pylib/run_python_tests.py
+++ b/media/webrtc/trunk/build/android/pylib/run_python_tests.py
@@ -9,16 +9,16 @@ import os
 import sys
 import types
 
-import android_commands
-import apk_info
-import constants
-import python_test_base
-from python_test_caller import CallPythonTest
-from python_test_sharder import PythonTestSharder
-import run_java_tests
-from run_java_tests import FatalTestException
-from test_info_collection import TestInfoCollection
-from test_result import TestResults
+from . import android_commands
+from . import apk_info
+from . import constants
+from . import python_test_base
+from .python_test_caller import CallPythonTest
+from .python_test_sharder import PythonTestSharder
+from . import run_java_tests
+from .run_java_tests import FatalTestException
+from .test_info_collection import TestInfoCollection
+from .test_result import TestResults
 
 
 def _GetPythonFiles(root, files):
@@ -155,7 +155,7 @@ def _GetTestsFromClass(test_class):
   """
   test_names = [m for m in dir(test_class)
                 if _IsTestMethod(m, test_class)]
-  return map(test_class, test_names)
+  return list(map(test_class, test_names))
 
 
 def _GetTestClassesFromModule(test_module):
@@ -168,7 +168,7 @@ def _GetTestClassesFromModule(test_module):
 
 
 def _IsTestClass(test_class):
-  return (type(test_class) is types.TypeType and
+  return (type(test_class) is type and
           issubclass(test_class, python_test_base.PythonTestBase) and
           test_class is not python_test_base.PythonTestBase)
 
diff --git a/media/webrtc/trunk/build/android/pylib/run_tests_helper.py b/media/webrtc/trunk/build/android/pylib/run_tests_helper.py
index 15e5d5381b..edb37ea656 100644
--- a/media/webrtc/trunk/build/android/pylib/run_tests_helper.py
+++ b/media/webrtc/trunk/build/android/pylib/run_tests_helper.py
@@ -12,7 +12,7 @@ def GetExpectations(file_name):
   """Returns a list of test names in the |file_name| test expectations file."""
   if not file_name or not os.path.exists(file_name):
     return []
-  return [x for x in [x.strip() for x in file(file_name).readlines()]
+  return [x for x in [x.strip() for x in open(file_name).readlines()]
           if x and x[0] != '#']
 
 
diff --git a/media/webrtc/trunk/build/android/pylib/sharded_tests_queue.py b/media/webrtc/trunk/build/android/pylib/sharded_tests_queue.py
index 9e28e2c484..8aff1698bc 100644
--- a/media/webrtc/trunk/build/android/pylib/sharded_tests_queue.py
+++ b/media/webrtc/trunk/build/android/pylib/sharded_tests_queue.py
@@ -27,7 +27,7 @@ class ShardedTestsQueue(object):
     self.tests_queue = multiprocessing.Queue()
     for test in tests:
       self.tests_queue.put(test)
-    for _ in xrange(self.num_devices):
+    for _ in range(self.num_devices):
       self.tests_queue.put(ShardedTestsQueue._STOP_SENTINEL)
 
   def __iter__(self):
diff --git a/media/webrtc/trunk/build/android/pylib/single_test_runner.py b/media/webrtc/trunk/build/android/pylib/single_test_runner.py
index a680c68f16..fda7d3328d 100644
--- a/media/webrtc/trunk/build/android/pylib/single_test_runner.py
+++ b/media/webrtc/trunk/build/android/pylib/single_test_runner.py
@@ -7,14 +7,14 @@ import logging
 import os
 import sys
 
-from base_test_runner import BaseTestRunner
-import debug_info
-import constants
-import perf_tests_helper
-import run_tests_helper
-from test_package_apk import TestPackageApk
-from test_package_executable import TestPackageExecutable
-from test_result import TestResults
+from .base_test_runner import BaseTestRunner
+from . import debug_info
+from . import constants
+from . import perf_tests_helper
+from . import run_tests_helper
+from .test_package_apk import TestPackageApk
+from .test_package_executable import TestPackageExecutable
+from .test_result import TestResults
 
 
 class SingleTestRunner(BaseTestRunner):
@@ -127,7 +127,7 @@ class SingleTestRunner(BaseTestRunner):
         os.unlink(filter_file_name)
       return
 
-    filter_file = file(filter_file_name, 'w')
+    filter_file = open(filter_file_name, 'w')
     if self._running_on_emulator:
       filter_file.write('# Addtional list of suppressions from emulator\n')
     else:
diff --git a/media/webrtc/trunk/build/android/pylib/test_info_collection.py b/media/webrtc/trunk/build/android/pylib/test_info_collection.py
index fc4e806941..315b4755fc 100644
--- a/media/webrtc/trunk/build/android/pylib/test_info_collection.py
+++ b/media/webrtc/trunk/build/android/pylib/test_info_collection.py
@@ -7,7 +7,7 @@
 import logging
 import os
 
-import tests_annotations
+from . import tests_annotations
 
 
 class TestInfo(object):
diff --git a/media/webrtc/trunk/build/android/pylib/test_options_parser.py b/media/webrtc/trunk/build/android/pylib/test_options_parser.py
index ee00f1fffd..e6dc3885c9 100644
--- a/media/webrtc/trunk/build/android/pylib/test_options_parser.py
+++ b/media/webrtc/trunk/build/android/pylib/test_options_parser.py
@@ -4,7 +4,7 @@
 
 """Parses options for the instrumentation tests."""
 
-import constants
+from . import constants
 import optparse
 import os
 import sys
diff --git a/media/webrtc/trunk/build/android/pylib/test_package.py b/media/webrtc/trunk/build/android/pylib/test_package.py
index a47ed72d89..b4ac58a4af 100644
--- a/media/webrtc/trunk/build/android/pylib/test_package.py
+++ b/media/webrtc/trunk/build/android/pylib/test_package.py
@@ -7,10 +7,10 @@ import logging
 import re
 import os
 
-import constants
-from perf_tests_helper import PrintPerfResult
+from . import constants
+from .perf_tests_helper import PrintPerfResult
 from pylib import pexpect
-from test_result import BaseTestResult, TestResults
+from .test_result import BaseTestResult, TestResults
 
 
 # TODO(bulach): TestPackage, TestPackageExecutable and
diff --git a/media/webrtc/trunk/build/android/pylib/test_package_apk.py b/media/webrtc/trunk/build/android/pylib/test_package_apk.py
index 42b9ade68b..9211a2225c 100644
--- a/media/webrtc/trunk/build/android/pylib/test_package_apk.py
+++ b/media/webrtc/trunk/build/android/pylib/test_package_apk.py
@@ -3,15 +3,16 @@
 # found in the LICENSE file.
 
 
+from __future__ import print_function
 import os
 import shlex
 import sys
 import tempfile
 import time
 
-import android_commands
-import constants
-from test_package import TestPackage
+from . import android_commands
+from . import constants
+from .test_package import TestPackage
 from pylib import pexpect
 
 class TestPackageApk(TestPackage):
@@ -61,7 +62,7 @@ class TestPackageApk(TestPackage):
   def _WatchFifo(self, timeout, logfile=None):
     for i in range(10):
       if self.adb.FileExistsOnDevice(self._GetFifo()):
-        print 'Fifo created...'
+        print('Fifo created...')
         break
       time.sleep(i)
     else:
diff --git a/media/webrtc/trunk/build/android/pylib/test_package_executable.py b/media/webrtc/trunk/build/android/pylib/test_package_executable.py
index a11c768fbb..36ea575f2b 100644
--- a/media/webrtc/trunk/build/android/pylib/test_package_executable.py
+++ b/media/webrtc/trunk/build/android/pylib/test_package_executable.py
@@ -9,9 +9,9 @@ import shutil
 import sys
 import tempfile
 
-import cmd_helper
-import constants
-from test_package import TestPackage
+from . import cmd_helper
+from . import constants
+from .test_package import TestPackage
 from pylib import pexpect
 
 
@@ -54,7 +54,7 @@ class TestPackageExecutable(TestPackage):
         logging.critical('Unable to pull gtest ret val file %s',
                          ret_code_file.name)
         raise ValueError
-      ret_code = file(ret_code_file.name).read()
+      ret_code = open(ret_code_file.name).read()
       ret = int(ret_code)
     except ValueError:
       logging.critical('Error reading gtest ret val file %s [%s]',
diff --git a/media/webrtc/trunk/build/android/pylib/test_result.py b/media/webrtc/trunk/build/android/pylib/test_result.py
index 31a546acac..0aa683f309 100644
--- a/media/webrtc/trunk/build/android/pylib/test_result.py
+++ b/media/webrtc/trunk/build/android/pylib/test_result.py
@@ -3,14 +3,15 @@
 # found in the LICENSE file.
 
 
+from __future__ import print_function
 import json
 import logging
 import os
 import time
 import traceback
 
-import buildbot_report
-import constants
+from . import buildbot_report
+from . import constants
 
 
 class BaseTestResult(object):
@@ -146,9 +147,9 @@ class TestResults(object):
       full_file_name = os.path.join(log_file_path, test_group)
       if not os.path.exists(full_file_name):
         with open(full_file_name, 'w') as log_file:
-          print >> log_file, '\n%s results for %s build %s:' % (
+          print('\n%s results for %s build %s:' % (
               test_group, os.environ.get('BUILDBOT_BUILDERNAME'),
-              os.environ.get('BUILDBOT_BUILDNUMBER'))
+              os.environ.get('BUILDBOT_BUILDNUMBER')), file=log_file)
       log_contents = ['  %s result : %d tests ran' % (test_suite,
                                                       len(self.ok) +
                                                       len(self.failed) +
@@ -160,14 +161,14 @@ class TestResults(object):
         if count:
           log_contents.append(', %d tests %s' % (count, result))
       with open(full_file_name, 'a') as log_file:
-        print >> log_file, ''.join(log_contents)
+        print(''.join(log_contents), file=log_file)
       content = {'test_group': test_group,
                  'ok': [t.name for t in self.ok],
                  'failed': [t.name for t in self.failed],
                  'crashed': [t.name for t in self.failed],
                  'unknown': [t.name for t in self.unknown],}
       with open(os.path.join(log_file_path, 'results.json'), 'a') as json_file:
-        print >> json_file, json.dumps(content)
+        print(json.dumps(content), file=json_file)
 
     # Summarize in the test output.
     summary_string = 'Summary:\n'
@@ -190,4 +191,4 @@ class TestResults(object):
     elif self.failed or self.crashed or self.overall_fail:
       buildbot_report.PrintError()
     else:
-      print 'Step success!'  # No annotation needed
+      print('Step success!')  # No annotation needed
diff --git a/media/webrtc/trunk/build/android/pylib/tests_annotations.py b/media/webrtc/trunk/build/android/pylib/tests_annotations.py
index f2a183466d..bac2b41179 100644
--- a/media/webrtc/trunk/build/android/pylib/tests_annotations.py
+++ b/media/webrtc/trunk/build/android/pylib/tests_annotations.py
@@ -23,7 +23,7 @@ class AnnotatedFunctions(object):
     """
     module_name = os.path.splitext(os.path.basename(
         function.__globals__['__file__']))[0]
-    qualified_function_name = '.'.join([module_name, function.func_name])
+    qualified_function_name = '.'.join([module_name, function.__name__])
     function_list = AnnotatedFunctions._ANNOTATED.get(annotation, [])
     function_list.append(qualified_function_name)
     AnnotatedFunctions._ANNOTATED[annotation] = function_list
@@ -52,7 +52,7 @@ class AnnotatedFunctions(object):
       List of all annotations for this function.
     """
     return [annotation
-            for annotation, tests in AnnotatedFunctions._ANNOTATED.iteritems()
+            for annotation, tests in AnnotatedFunctions._ANNOTATED.items()
             if qualified_function_name in tests]
 
 
diff --git a/media/webrtc/trunk/build/android/pylib/valgrind_tools.py b/media/webrtc/trunk/build/android/pylib/valgrind_tools.py
index 810f6be188..43a8b25f9d 100644
--- a/media/webrtc/trunk/build/android/pylib/valgrind_tools.py
+++ b/media/webrtc/trunk/build/android/pylib/valgrind_tools.py
@@ -21,10 +21,11 @@ Run the test as usual.
 Call tool.CleanUpEnvironment().
 """
 
+from __future__ import print_function
 import os.path
 import sys
 
-from constants import CHROME_DIR
+from .constants import CHROME_DIR
 
 
 def SetChromeTimeoutScale(adb, scale):
@@ -250,6 +251,6 @@ def CreateTool(tool_name, adb):
   if ctor:
     return ctor(adb)
   else:
-    print 'Unknown tool %s, available tools: %s' % (
-        tool_name, ', '.join(sorted(TOOL_REGISTRY.keys())))
+    print('Unknown tool %s, available tools: %s' % (
+        tool_name, ', '.join(sorted(TOOL_REGISTRY.keys()))))
     sys.exit(1)
diff --git a/media/webrtc/trunk/build/android/run_tests.py b/media/webrtc/trunk/build/android/run_tests.py
index 8a8bd26954..37fae2e227 100755
--- a/media/webrtc/trunk/build/android/run_tests.py
+++ b/media/webrtc/trunk/build/android/run_tests.py
@@ -49,6 +49,7 @@ loaded. We don't care about the rare testcases which succeeded on emuatlor, but
 failed on device.
 """
 
+from __future__ import print_function
 import fnmatch
 import logging
 import optparse
@@ -220,10 +221,8 @@ class TestSharder(BaseTestSharder):
       if not rebaseline:
         disabled_list = test.GetDisabledTests()
         # Only includes tests that do not have any match in the disabled list.
-        all_tests = filter(lambda t:
-                           not any([fnmatch.fnmatch(t, disabled_pattern)
-                                    for disabled_pattern in disabled_list]),
-                           all_tests)
+        all_tests = [t for t in all_tests if not any([fnmatch.fnmatch(t, disabled_pattern)
+                                    for disabled_pattern in disabled_list])]
       self.tests = all_tests
 
   def CreateShardedTestRunner(self, device, index):
@@ -292,8 +291,8 @@ def _RunATestSuite(options):
       buildbot_emulators.append(buildbot_emulator)
       attached_devices.append(buildbot_emulator.device)
     # Wait for all emulators to boot completed.
-    map(lambda buildbot_emulator: buildbot_emulator.ConfirmLaunch(True),
-        buildbot_emulators)
+    list(map(lambda buildbot_emulator: buildbot_emulator.ConfirmLaunch(True),
+        buildbot_emulators))
   elif options.test_device:
     attached_devices = [options.test_device]
   else:
@@ -370,9 +369,9 @@ def Dispatch(options):
 
 def ListTestSuites():
   """Display a list of available test suites."""
-  print 'Available test suites are:'
+  print('Available test suites are:')
   for test_suite in _TEST_SUITES:
-    print test_suite
+    print(test_suite)
 
 
 def main(argv):
@@ -427,7 +426,7 @@ def main(argv):
 
   options, args = option_parser.parse_args(argv)
   if len(args) > 1:
-    print 'Unknown argument:', args[1:]
+    print('Unknown argument:', args[1:])
     option_parser.print_usage()
     sys.exit(1)
   run_tests_helper.SetLogLevel(options.verbose_count)
diff --git a/media/webrtc/trunk/build/apply_locales.py b/media/webrtc/trunk/build/apply_locales.py
index 6af7280fad..7dd80152be 100755
--- a/media/webrtc/trunk/build/apply_locales.py
+++ b/media/webrtc/trunk/build/apply_locales.py
@@ -5,6 +5,7 @@
 
 # TODO: remove this script when GYP has for loops
 
+from __future__ import print_function
 import sys
 import optparse
 
@@ -20,7 +21,7 @@ def main(argv):
   (options, arglist) = parser.parse_args(argv)
 
   if len(arglist) < 3:
-    print 'ERROR: need string and list of locales'
+    print('ERROR: need string and list of locales')
     return 1
 
   str_template = arglist[1]
@@ -39,7 +40,7 @@ def main(argv):
 
   # Quote each element so filename spaces don't mess up GYP's attempt to parse
   # it into a list.
-  print ' '.join(["'%s'" % x for x in results])
+  print(' '.join(["'%s'" % x for x in results]))
 
 if __name__ == '__main__':
   sys.exit(main(sys.argv))
diff --git a/media/webrtc/trunk/build/compiler_version.py b/media/webrtc/trunk/build/compiler_version.py
index eae7b176dd..dabfe0f2a5 100755
--- a/media/webrtc/trunk/build/compiler_version.py
+++ b/media/webrtc/trunk/build/compiler_version.py
@@ -9,6 +9,7 @@ Print gcc version as XY if you are running gcc X.Y.*.
 This is used to tweak build flags for gcc 4.4.
 """
 
+from __future__ import print_function
 import os
 import re
 import subprocess
@@ -26,11 +27,11 @@ def GetVersion(compiler):
 
     result = re.match(r"(\d+)\.(\d+)", gcc_output)
     return result.group(1) + result.group(2)
-  except Exception, e:
+  except Exception as e:
     if gcc_error:
       sys.stderr.write(gcc_error)
-    print >> sys.stderr, "compiler_version.py failed to execute:", compiler
-    print >> sys.stderr, e
+    print("compiler_version.py failed to execute:", compiler, file=sys.stderr)
+    print(e, file=sys.stderr)
     return ""
 
 def GetVersionFromEnvironment(compiler_env):
@@ -56,18 +57,18 @@ def main():
   # target compiler's version number as gcc_version in Android.
   cxx_version = GetVersionFromEnvironment("CXX_target")
   if cxx_version:
-    print cxx_version
+    print(cxx_version)
     return 0
 
   cxx_version = GetVersionFromEnvironment("CXX")
   if cxx_version:
-    print cxx_version
+    print(cxx_version)
     return 0
 
   # Otherwise we check the g++ version.
   gccversion = GetVersion("g++")
   if gccversion != "":
-    print gccversion
+    print(gccversion)
     return 0
 
   return 1
diff --git a/media/webrtc/trunk/build/copy_test_data_ios.py b/media/webrtc/trunk/build/copy_test_data_ios.py
index 5130735835..d4485cefcc 100755
--- a/media/webrtc/trunk/build/copy_test_data_ios.py
+++ b/media/webrtc/trunk/build/copy_test_data_ios.py
@@ -5,6 +5,7 @@
 
 """Copies test data files or directories into a given output directory."""
 
+from __future__ import print_function
 import optparse
 import os
 import shutil
@@ -93,11 +94,11 @@ def DoMain(argv):
 def main(argv):
   try:
     result = DoMain(argv[1:])
-  except WrongNumberOfArgumentsException, e:
-    print >>sys.stderr, e
+  except WrongNumberOfArgumentsException as e:
+    print(e, file=sys.stderr)
     return 1
   if result:
-    print result
+    print(result)
   return 0
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/build/download_nacl_toolchains.py b/media/webrtc/trunk/build/download_nacl_toolchains.py
index c2007d0f10..c52a2db803 100755
--- a/media/webrtc/trunk/build/download_nacl_toolchains.py
+++ b/media/webrtc/trunk/build/download_nacl_toolchains.py
@@ -5,6 +5,7 @@
 
 """Shim to run nacl toolchain download script only if there is a nacl dir."""
 
+from __future__ import print_function
 import os
 import sys
 
@@ -19,9 +20,9 @@ def Main(args):
   nacl_build_dir = os.path.join(nacl_dir, 'build')
   download_script = os.path.join(nacl_build_dir, 'download_toolchains.py')
   if not os.path.exists(download_script):
-    print "Can't find '%s'" % download_script
-    print 'Presumably you are intentionally building without NativeClient.'
-    print 'Skipping NativeClient toolchain download.'
+    print("Can't find '%s'" % download_script)
+    print('Presumably you are intentionally building without NativeClient.')
+    print('Skipping NativeClient toolchain download.')
     sys.exit(0)
   sys.path.insert(0, nacl_build_dir)
   import download_toolchains
@@ -46,7 +47,7 @@ def Main(args):
     if buildbot_name.find('pnacl') >= 0 and  buildbot_name.find('sdk') >= 0:
       use_pnacl = True
     if use_pnacl:
-      print '\n*** DOWNLOADING PNACL TOOLCHAIN ***\n'
+      print('\n*** DOWNLOADING PNACL TOOLCHAIN ***\n')
     else:
       args.append('--no-pnacl')
 
diff --git a/media/webrtc/trunk/build/escape_unicode.py b/media/webrtc/trunk/build/escape_unicode.py
index 859ba5d03d..2fe5947c68 100755
--- a/media/webrtc/trunk/build/escape_unicode.py
+++ b/media/webrtc/trunk/build/escape_unicode.py
@@ -5,6 +5,7 @@
 
 """Convert any unicode characters found in the input file to C literals."""
 
+from __future__ import print_function
 import codecs
 import optparse
 import os
@@ -20,17 +21,17 @@ def main(argv):
   options, arglist = parser.parse_args(argv)
 
   if not options.output_dir:
-    print "output_dir required"
+    print("output_dir required")
     return 1
 
   if len(arglist) != 2:
-    print "input_file required"
+    print("input_file required")
     return 1
 
   in_filename = arglist[1]
 
   if not in_filename.endswith('.utf8'):
-    print "input_file should end in .utf8"
+    print("input_file should end in .utf8")
     return 1
 
   out_filename = os.path.join(options.output_dir, os.path.basename(
diff --git a/media/webrtc/trunk/build/extract_from_cab.py b/media/webrtc/trunk/build/extract_from_cab.py
index 1c928af36f..fd781c733b 100755
--- a/media/webrtc/trunk/build/extract_from_cab.py
+++ b/media/webrtc/trunk/build/extract_from_cab.py
@@ -5,6 +5,7 @@
 
 """Extracts a single file from a CAB archive."""
 
+from __future__ import print_function
 import os
 import shutil
 import subprocess
@@ -17,12 +18,12 @@ def run_quiet(*args):
   out, _ = popen.communicate()
   if popen.returncode:
     # expand emits errors to stdout, so if we fail, then print that out.
-    print out
+    print(out)
   return popen.returncode
 
 def main():
   if len(sys.argv) != 4:
-    print 'Usage: extract_from_cab.py cab_path archived_file output_dir'
+    print('Usage: extract_from_cab.py cab_path archived_file output_dir')
     return 1
 
   [cab_path, archived_file, output_dir] = sys.argv[1:]
diff --git a/media/webrtc/trunk/build/linux/rewrite_dirs.py b/media/webrtc/trunk/build/linux/rewrite_dirs.py
index 30f22f0cd6..7faf4ca944 100755
--- a/media/webrtc/trunk/build/linux/rewrite_dirs.py
+++ b/media/webrtc/trunk/build/linux/rewrite_dirs.py
@@ -5,6 +5,7 @@
 
 """Rewrites paths in -I, -L and other option to be relative to a sysroot."""
 
+from __future__ import print_function
 import sys
 import os
 import optparse
@@ -63,7 +64,7 @@ def main(argv):
 
   for line in sys.stdin.readlines():
     line = RewriteLine(line.strip(), opts)
-    print line
+    print(line)
   return 0
 
 
diff --git a/media/webrtc/trunk/build/mac/change_mach_o_flags.py b/media/webrtc/trunk/build/mac/change_mach_o_flags.py
index c2aeaec9b1..a0d455d703 100755
--- a/media/webrtc/trunk/build/mac/change_mach_o_flags.py
+++ b/media/webrtc/trunk/build/mac/change_mach_o_flags.py
@@ -106,8 +106,7 @@ def CheckedSeek(file, offset):
   file.seek(offset, os.SEEK_SET)
   new_offset = file.tell()
   if new_offset != offset:
-    raise MachOError, \
-          'seek: expected offset %d, observed %d' % (offset, new_offset)
+    raise MachOError('seek: expected offset %d, observed %d' % (offset, new_offset))
 
 
 def CheckedRead(file, count):
@@ -116,8 +115,7 @@ def CheckedRead(file, count):
 
   bytes = file.read(count)
   if len(bytes) != count:
-    raise MachOError, \
-          'read: expected length %d, observed %d' % (count, len(bytes))
+    raise MachOError('read: expected length %d, observed %d' % (count, len(bytes)))
 
   return bytes
 
@@ -189,17 +187,15 @@ def HandleMachOFile(file, options, offset=0):
   elif magic == MH_CIGAM or magic == MH_CIGAM_64:
     endian = '>'
   else:
-    raise MachOError, \
-          'Mach-O file at offset %d has illusion of magic' % offset
+    raise MachOError('Mach-O file at offset %d has illusion of magic' % offset)
 
   CheckedSeek(file, offset)
   magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
       ReadMachHeader(file, endian)
   assert magic == MH_MAGIC or magic == MH_MAGIC_64
   if filetype != MH_EXECUTE:
-    raise MachOError, \
-          'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
-              (offset, filetype)
+    raise MachOError('Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
+              (offset, filetype))
 
   original_flags = flags
 
@@ -228,7 +224,7 @@ def HandleFatFile(file, options, fat_offset=0):
 
   nfat_arch = ReadUInt32(file, '>')
 
-  for index in xrange(0, nfat_arch):
+  for index in range(0, nfat_arch):
     cputype, cpusubtype, offset, size, align = ReadFatArch(file)
     assert size >= 28
 
@@ -263,7 +259,7 @@ def main(me, args):
       magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
     HandleMachOFile(executable_file, options)
   else:
-    raise MachOError, '%s is not a Mach-O or fat file' % executable_file
+    raise MachOError('%s is not a Mach-O or fat file' % executable_file)
 
   executable_file.close()
   return 0
diff --git a/media/webrtc/trunk/build/mac/find_sdk.py b/media/webrtc/trunk/build/mac/find_sdk.py
index 5be134a707..e9a318c236 100755
--- a/media/webrtc/trunk/build/mac/find_sdk.py
+++ b/media/webrtc/trunk/build/mac/find_sdk.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 import os
 import re
 import subprocess
@@ -20,7 +21,7 @@ from optparse import OptionParser
 
 def parse_version(version_str):
   """'10.5' => [10, 5]"""
-  return map(int, re.findall(r'(\d+)', version_str))
+  return list(map(int, re.findall(r'(\d+)', version_str)))
 
 
 def main():
@@ -40,8 +41,8 @@ def main():
                            stderr=subprocess.STDOUT)
     out, err = job.communicate()
     if job.returncode != 0:
-      print >>sys.stderr, out
-      print >>sys.stderr, err
+      print(out, file=sys.stderr)
+      print(err, file=sys.stderr)
       raise Exception(('Error %d running xcode-select, you might have to run '
                        '|sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer| '
                        'if you are using Xcode 4.') % job.returncode)
@@ -63,21 +64,19 @@ def main():
     best_sdk = ""
 
   if options.verify and best_sdk != min_sdk_version and not options.sdk_path:
-    print >>sys.stderr, ''
-    print >>sys.stderr, '                                           vvvvvvv'
-    print >>sys.stderr, ''
-    print >>sys.stderr, \
-        'This build requires the %s SDK, but it was not found on your system.' \
-        % min_sdk_version
-    print >>sys.stderr, \
-        'Either install it, or explicitly set mac_sdk in your GYP_DEFINES.'
-    print >>sys.stderr, ''
-    print >>sys.stderr, '                                           ^^^^^^^'
-    print >>sys.stderr, ''
+    print('', file=sys.stderr)
+    print('                                           vvvvvvv', file=sys.stderr)
+    print('', file=sys.stderr)
+    print('This build requires the %s SDK, but it was not found on your system.' \
+        % min_sdk_version, file=sys.stderr)
+    print('Either install it, or explicitly set mac_sdk in your GYP_DEFINES.', file=sys.stderr)
+    print('', file=sys.stderr)
+    print('                                           ^^^^^^^', file=sys.stderr)
+    print('', file=sys.stderr)
     return min_sdk_version
 
   return best_sdk
 
 
 if __name__ == '__main__':
-  print main()
+  print(main())
diff --git a/media/webrtc/trunk/build/mac/tweak_info_plist.py b/media/webrtc/trunk/build/mac/tweak_info_plist.py
index 9b57e7da01..751f3214fc 100755
--- a/media/webrtc/trunk/build/mac/tweak_info_plist.py
+++ b/media/webrtc/trunk/build/mac/tweak_info_plist.py
@@ -20,6 +20,7 @@
 # by the time the app target is done, the info.plist is correct.
 #
 
+from __future__ import print_function
 import optparse
 import os
 from os import environ as env
@@ -115,7 +116,7 @@ def _DoSCMKeys(plist, add_keys):
   if scm_revision != None:
     plist['SCMRevision'] = scm_revision
   elif add_keys:
-    print >>sys.stderr, 'Could not determine SCM revision.  This may be OK.'
+    print('Could not determine SCM revision.  This may be OK.', file=sys.stderr)
 
   if scm_path != None:
     plist['SCMPath'] = scm_path
@@ -232,7 +233,7 @@ def Main(argv):
   (options, args) = parser.parse_args(argv)
 
   if len(args) > 0:
-    print >>sys.stderr, parser.get_usage()
+    print(parser.get_usage(), file=sys.stderr)
     return 1
 
   # Read the plist into its parsed format.
@@ -246,7 +247,7 @@ def Main(argv):
   # Add Breakpad if configured to do so.
   if options.use_breakpad:
     if options.branding is None:
-      print >>sys.stderr, 'Use of Breakpad requires branding.'
+      print('Use of Breakpad requires branding.', file=sys.stderr)
       return 1
     _AddBreakpadKeys(plist, options.branding)
     if options.breakpad_uploads:
@@ -265,7 +266,7 @@ def Main(argv):
   # Only add Keystone in Release builds.
   if options.use_keystone and env['CONFIGURATION'] == 'Release':
     if options.bundle_identifier is None:
-      print >>sys.stderr, 'Use of Keystone requires the bundle id.'
+      print('Use of Keystone requires the bundle id.', file=sys.stderr)
       return 1
     _AddKeystoneKeys(plist, options.bundle_identifier)
   else:
diff --git a/media/webrtc/trunk/build/util/lastchange.py b/media/webrtc/trunk/build/util/lastchange.py
index a101341ef7..5ca702f053 100755
--- a/media/webrtc/trunk/build/util/lastchange.py
+++ b/media/webrtc/trunk/build/util/lastchange.py
@@ -7,6 +7,7 @@
 lastchange.py -- Chromium revision fetching utility.
 """
 
+from __future__ import print_function
 import re
 import optparse
 import os
@@ -215,7 +216,7 @@ def main(argv=None):
     version_info.revision = '0'
 
   if opts.revision_only:
-    print version_info.revision
+    print(version_info.revision)
   else:
     contents = "LASTCHANGE=%s\n" % version_info.revision
     if out_file:
diff --git a/media/webrtc/trunk/build/win/install-build-deps.py b/media/webrtc/trunk/build/win/install-build-deps.py
index d9e50b6e7e..a976b81db3 100755
--- a/media/webrtc/trunk/build/win/install-build-deps.py
+++ b/media/webrtc/trunk/build/win/install-build-deps.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 import shutil
 import sys
 import os
@@ -18,11 +19,11 @@ def patch_msbuild():
   backup_path = source_path + ".backup"
   if not os.path.exists(backup_path):
     try:
-      print "Backing up %s..." % source_path
+      print("Backing up %s..." % source_path)
       shutil.copyfile(source_path, backup_path)
     except IOError:
-      print "Could not back up %s to %s. Run as Administrator?" % (
-          source_path, backup_path)
+      print("Could not back up %s to %s. Run as Administrator?" % (
+          source_path, backup_path))
       return 1
 
   source = open(source_path).read()
@@ -35,7 +36,7 @@ def patch_msbuild():
 
   if result != source:
     open(source_path, "w").write(result)
-    print "Patched %s." % source_path
+    print("Patched %s." % source_path)
   return 0
 
 
diff --git a/media/webrtc/trunk/google_apis/build/check_internal.py b/media/webrtc/trunk/google_apis/build/check_internal.py
index da0ddae805..5a43944921 100755
--- a/media/webrtc/trunk/google_apis/build/check_internal.py
+++ b/media/webrtc/trunk/google_apis/build/check_internal.py
@@ -9,12 +9,13 @@ Takes one argument, a path.  Prints 1 if the path exists, 0 if not.
 """
 
 
+from __future__ import print_function
 import os
 import sys
 
 
 if __name__ == '__main__':
   if os.path.exists(sys.argv[1]):
-    print 1
+    print(1)
   else:
-    print 0
+    print(0)
diff --git a/media/webrtc/trunk/testing/generate_gmock_mutant.py b/media/webrtc/trunk/testing/generate_gmock_mutant.py
index 01176da39b..7b1756d333 100755
--- a/media/webrtc/trunk/testing/generate_gmock_mutant.py
+++ b/media/webrtc/trunk/testing/generate_gmock_mutant.py
@@ -376,7 +376,7 @@ def FixCode(s):
 
 
 def GenerateDispatch(prebound, calltime):
-  print "\n// %d - %d" % (prebound, calltime)
+  print("\n// %d - %d" % (prebound, calltime))
   args = {
       "template_params": Merge([Gen("typename P%", prebound),
                                 Gen("typename C%", calltime)]),
@@ -385,12 +385,12 @@ def GenerateDispatch(prebound, calltime):
       "args": Merge([GenAlpha("p.%", prebound), GenAlpha("c.%", calltime)]),
   }
 
-  print FixCode(DISPATCH_TO_METHOD_TEMPLATE % args)
-  print FixCode(DISPATCH_TO_FUNCTION_TEMPLATE % args)
+  print(FixCode(DISPATCH_TO_METHOD_TEMPLATE % args))
+  print(FixCode(DISPATCH_TO_FUNCTION_TEMPLATE % args))
 
 
 def GenerateCreateFunctor(prebound, calltime):
-  print "// %d - %d" % (prebound, calltime)
+  print("// %d - %d" % (prebound, calltime))
   args = {
       "calltime": GenTuple("A%", calltime),
       "prebound": GenTuple("P%", prebound),
@@ -403,51 +403,51 @@ def GenerateCreateFunctor(prebound, calltime):
   }
 
   mutant = FixCode(CREATE_METHOD_FUNCTOR_TEMPLATE % args)
-  print mutant
+  print(mutant)
 
   # Slightly different version for free function call.
-  print "\n", FixCode(CREATE_FUNCTION_FUNCTOR_TEMPLATE % args)
+  print("\n", FixCode(CREATE_FUNCTION_FUNCTOR_TEMPLATE % args))
 
   # Functor with pointer to a pointer of the object.
-  print "\n#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING"
+  print("\n#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING")
   mutant2 = mutant.replace("CreateFunctor(T* obj,", "CreateFunctor(T** obj,")
   mutant2 = mutant2.replace("new Mutant", "new MutantLateObjectBind")
   mutant2 = mutant2.replace(" " * 17 + "Tuple", " " * 31 + "Tuple")
-  print mutant2
-  print "#endif  // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING\n"
+  print(mutant2)
+  print("#endif  // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING\n")
 
   # OS_WIN specific. Same functors but with stdcall calling conventions.
   # Functor for method with __stdcall calling conventions.
-  print "#if defined (OS_WIN)"
+  print("#if defined (OS_WIN)")
   stdcall_method = CREATE_METHOD_FUNCTOR_TEMPLATE
   stdcall_method = stdcall_method.replace("U::", "__stdcall U::")
   stdcall_method = FixCode(stdcall_method % args)
-  print stdcall_method
+  print(stdcall_method)
   # Functor for free function with __stdcall calling conventions.
   stdcall_function = CREATE_FUNCTION_FUNCTOR_TEMPLATE
   stdcall_function = stdcall_function.replace("R (*", "R (__stdcall *");
-  print "\n", FixCode(stdcall_function % args)
+  print("\n", FixCode(stdcall_function % args))
 
-  print "#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING"
+  print("#ifdef GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING")
   stdcall2 = stdcall_method;
   stdcall2 = stdcall2.replace("CreateFunctor(T* obj,", "CreateFunctor(T** obj,")
   stdcall2 = stdcall2.replace("new Mutant", "new MutantLateObjectBind")
   stdcall2 = stdcall2.replace(" " * 17 + "Tuple", " " * 31 + "Tuple")
-  print stdcall2
-  print "#endif  // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING"
-  print "#endif  // OS_WIN\n"
+  print(stdcall2)
+  print("#endif  // GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING")
+  print("#endif  // OS_WIN\n")
 
 
 def main():
-  print HEADER
-  for prebound in xrange(0, 6 + 1):
-    for args in xrange(0, 6 + 1):
+  print(HEADER)
+  for prebound in range(0, 6 + 1):
+    for args in range(0, 6 + 1):
       GenerateDispatch(prebound, args)
-  print MUTANT
-  for prebound in xrange(0, 6 + 1):
-    for args in xrange(0, 6 + 1):
+  print(MUTANT)
+  for prebound in range(0, 6 + 1):
+    for args in range(0, 6 + 1):
       GenerateCreateFunctor(prebound, args)
-  print FOOTER
+  print(FOOTER)
   return 0
 
 
diff --git a/media/webrtc/trunk/testing/gtest/scripts/fuse_gtest_files.py b/media/webrtc/trunk/testing/gtest/scripts/fuse_gtest_files.py
index 57ef72f0e3..f1ff68c4d8 100755
--- a/media/webrtc/trunk/testing/gtest/scripts/fuse_gtest_files.py
+++ b/media/webrtc/trunk/testing/gtest/scripts/fuse_gtest_files.py
@@ -90,8 +90,8 @@ def VerifyFileExists(directory, relative_path):
   """
 
   if not os.path.isfile(os.path.join(directory, relative_path)):
-    print 'ERROR: Cannot find %s in directory %s.' % (relative_path,
-                                                      directory)
+    print('ERROR: Cannot find {} in directory {}.'.format(relative_path,
+                                                      directory))
     print ('Please either specify a valid project root directory '
            'or omit it on the command line.')
     sys.exit(1)
@@ -119,11 +119,11 @@ def VerifyOutputFile(output_dir, relative_path):
     # TODO(wan@google.com): The following user-interaction doesn't
     # work with automated processes.  We should provide a way for the
     # Makefile to force overwriting the files.
-    print ('%s already exists in directory %s - overwrite it? (y/N) ' %
+    print('%s already exists in directory %s - overwrite it? (y/N) ' %
            (relative_path, output_dir))
     answer = sys.stdin.readline().strip()
     if answer not in ['y', 'Y']:
-      print 'ABORTED.'
+      print('ABORTED.')
       sys.exit(1)
 
   # Makes sure the directory holding the output file exists; creates
@@ -146,7 +146,7 @@ def ValidateOutputDir(output_dir):
 def FuseGTestH(gtest_root, output_dir):
   """Scans folder gtest_root to generate gtest/gtest.h in output_dir."""
 
-  output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w')
+  output_file = open(os.path.join(output_dir, GTEST_H_OUTPUT), 'w')
   processed_files = sets.Set()  # Holds all gtest headers we've processed.
 
   def ProcessFile(gtest_header_path):
@@ -159,7 +159,7 @@ def FuseGTestH(gtest_root, output_dir):
     processed_files.add(gtest_header_path)
 
     # Reads each line in the given gtest header.
-    for line in file(os.path.join(gtest_root, gtest_header_path), 'r'):
+    for line in open(os.path.join(gtest_root, gtest_header_path)):
       m = INCLUDE_GTEST_FILE_REGEX.match(line)
       if m:
         # It's '#include "gtest/..."' - let's process it recursively.
@@ -187,7 +187,7 @@ def FuseGTestAllCcToFile(gtest_root, output_file):
     processed_files.add(gtest_source_file)
 
     # Reads each line in the given gtest source file.
-    for line in file(os.path.join(gtest_root, gtest_source_file), 'r'):
+    for line in open(os.path.join(gtest_root, gtest_source_file)):
       m = INCLUDE_GTEST_FILE_REGEX.match(line)
       if m:
         if 'include/' + m.group(1) == GTEST_SPI_H_SEED:
@@ -203,7 +203,7 @@ def FuseGTestAllCcToFile(gtest_root, output_file):
           # There is no need to #include "gtest/gtest.h" more than once.
           if not GTEST_H_SEED in processed_files:
             processed_files.add(GTEST_H_SEED)
-            output_file.write('#include "%s"\n' % (GTEST_H_OUTPUT,))
+            output_file.write('#include "{}"\n'.format(GTEST_H_OUTPUT))
       else:
         m = INCLUDE_SRC_FILE_REGEX.match(line)
         if m:
@@ -218,7 +218,7 @@ def FuseGTestAllCcToFile(gtest_root, output_file):
 def FuseGTestAllCc(gtest_root, output_dir):
   """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir."""
 
-  output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w')
+  output_file = open(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w')
   FuseGTestAllCcToFile(gtest_root, output_file)
   output_file.close()
 
@@ -242,7 +242,7 @@ def main():
     # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR
     FuseGTest(sys.argv[1], sys.argv[2])
   else:
-    print __doc__
+    print(__doc__)
     sys.exit(1)
 
 
diff --git a/media/webrtc/trunk/testing/gtest/scripts/gen_gtest_pred_impl.py b/media/webrtc/trunk/testing/gtest/scripts/gen_gtest_pred_impl.py
index 3e7ab042ea..a34c529163 100755
--- a/media/webrtc/trunk/testing/gtest/scripts/gen_gtest_pred_impl.py
+++ b/media/webrtc/trunk/testing/gtest/scripts/gen_gtest_pred_impl.py
@@ -73,7 +73,7 @@ def HeaderPreamble(n):
   DEFS = {
     'today' : time.strftime('%m/%d/%Y'),
     'year' : time.strftime('%Y'),
-    'command' : '%s %s' % (os.path.basename(sys.argv[0]), n),
+    'command' : '{} {}'.format(os.path.basename(sys.argv[0]), n),
     'n' : n
     }
 
@@ -183,7 +183,7 @@ def Title(word):
 def OneTo(n):
   """Returns the list [1, 2, 3, ..., n]."""
 
-  return range(1, n + 1)
+  return list(range(1, n + 1))
 
 
 def Iter(n, format, sep=''):
@@ -303,13 +303,13 @@ def GenerateFile(path, content):
   """Given a file path and a content string, overwrites it with the
   given content."""
 
-  print 'Updating file %s . . .' % path
+  print('Updating file %s . . .' % path)
 
-  f = file(path, 'w+')
-  print >>f, content,
+  f = open(path, 'w+')
+  print(content, end=' ', file=f)
   f.close()
 
-  print 'File %s has been updated.' % path
+  print('File %s has been updated.' % path)
 
 
 def GenerateHeader(n):
@@ -329,7 +329,7 @@ def UnitTestPreamble():
   DEFS = {
     'today' : time.strftime('%m/%d/%Y'),
     'year' : time.strftime('%Y'),
-    'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]),
+    'command' : '{} {}'.format(os.path.basename(sys.argv[0]), sys.argv[1]),
     }
 
   return (
@@ -525,9 +525,9 @@ class Predicate%(n)sTest : public testing::Test {
     // exactly once."""
 
   tests += ''.join(["""
-    EXPECT_EQ(1, n%s_) <<
-        "The predicate assertion didn't evaluate argument %s "
-        "exactly once.";""" % (i, i + 1) for i in OneTo(n)])
+    EXPECT_EQ(1, n{}_) <<
+        "The predicate assertion didn't evaluate argument {} "
+        "exactly once.";""".format(i, i + 1) for i in OneTo(n)])
 
   tests += """
 
@@ -717,8 +717,8 @@ def _Main():
   unit test."""
 
   if len(sys.argv) != 2:
-    print __doc__
-    print 'Author: ' + __author__
+    print(__doc__)
+    print('Author: ' + __author__)
     sys.exit(1)
 
   n = int(sys.argv[1])
diff --git a/media/webrtc/trunk/testing/gtest/scripts/pump.py b/media/webrtc/trunk/testing/gtest/scripts/pump.py
index 5efb653c20..fc7577bf8b 100755
--- a/media/webrtc/trunk/testing/gtest/scripts/pump.py
+++ b/media/webrtc/trunk/testing/gtest/scripts/pump.py
@@ -114,7 +114,7 @@ class Cursor:
     if self == Eof():
       return 'EOF'
     else:
-      return '%s(%s)' % (self.line + 1, self.column)
+      return '{}({})'.format(self.line + 1, self.column)
 
   def __add__(self, offset):
     return Cursor(self.line, self.column + offset)
@@ -150,7 +150,7 @@ class Token:
     self.token_type = token_type
 
   def __str__(self):
-    return 'Token @%s: \'%s\' type=%s' % (
+    return 'Token @{}: \'{}\' type={}'.format(
         self.start, self.value, self.token_type)
 
   def Clone(self):
@@ -246,7 +246,7 @@ def ParseToken(lines, pos, regex, token_type):
   if m and not m.start():
     return MakeToken(lines, pos, pos + m.end(), token_type)
   else:
-    print 'ERROR: %s expected at %s.' % (token_type, pos)
+    print('ERROR: {} expected at {}.'.format(token_type, pos))
     sys.exit(1)
 
 
@@ -273,7 +273,7 @@ def SkipUntil(lines, pos, regex, token_type):
   if m:
     return pos + m.start()
   else:
-    print ('ERROR: %s expected on line %s after column %s.' %
+    print('ERROR: %s expected on line %s after column %s.' %
            (token_type, pos.line + 1, pos.column))
     sys.exit(1)
 
@@ -383,8 +383,7 @@ def Tokenize(s):
   """A generator that yields the tokens in the given string."""
   if s != '':
     lines = s.splitlines(True)
-    for token in TokenizeLines(lines, Cursor(0, 0)):
-      yield token
+    yield from TokenizeLines(lines, Cursor(0, 0))
 
 
 class CodeNode:
@@ -453,8 +452,8 @@ def PushFront(a_list, elem):
 def PopToken(a_list, token_type=None):
   token = PopFront(a_list)
   if token_type is not None and token.token_type != token_type:
-    print 'ERROR: %s expected at %s' % (token_type, token.start)
-    print 'ERROR: %s found instead' % (token,)
+    print('ERROR: {} expected at {}'.format(token_type, token.start))
+    print('ERROR: {} found instead'.format(token))
     sys.exit(1)
 
   return token
@@ -616,15 +615,15 @@ class Env:
       if identifier == var:
         return value
 
-    print 'ERROR: meta variable %s is undefined.' % (identifier,)
+    print('ERROR: meta variable {} is undefined.'.format(identifier))
     sys.exit(1)
 
   def EvalExp(self, exp):
     try:
       result = eval(exp.python_exp)
-    except Exception, e:
-      print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e)
-      print ('ERROR: failed to evaluate meta expression %s at %s' %
+    except Exception as e:
+      print('ERROR: caught exception {}: {}'.format(e.__class__.__name__, e))
+      print('ERROR: failed to evaluate meta expression %s at %s' %
              (exp.python_exp, exp.token.start))
       sys.exit(1)
     return result
@@ -634,7 +633,7 @@ class Env:
       if identifier == var:
         return (lower, upper)
 
-    print 'ERROR: range %s is undefined.' % (identifier,)
+    print('ERROR: range {} is undefined.'.format(identifier))
     sys.exit(1)
 
 
@@ -688,14 +687,14 @@ def RunAtomicCode(env, node, output):
       RunCode(env.Clone(), node.else_branch, output)
   elif isinstance(node, ExpNode):
     value = env.EvalExp(node)
-    output.Append('%s' % (value,))
+    output.Append('{}'.format(value))
   elif isinstance(node, LiteralDollarNode):
     output.Append('$')
   elif isinstance(node, CodeNode):
     RunCode(env.Clone(), node, output)
   else:
-    print 'BAD'
-    print node
+    print('BAD')
+    print(node)
     sys.exit(1)
 
 
@@ -830,19 +829,19 @@ def ConvertFromPumpSource(src_text):
 
 def main(argv):
   if len(argv) == 1:
-    print __doc__
+    print(__doc__)
     sys.exit(1)
 
   file_path = argv[-1]
-  output_str = ConvertFromPumpSource(file(file_path, 'r').read())
+  output_str = ConvertFromPumpSource(open(file_path).read())
   if file_path.endswith('.pump'):
     output_file_path = file_path[:-5]
   else:
     output_file_path = '-'
   if output_file_path == '-':
-    print output_str,
+    print(output_str, end=' ')
   else:
-    output_file = file(output_file_path, 'w')
+    output_file = open(output_file_path, 'w')
     output_file.write('// This file was GENERATED by command:\n')
     output_file.write('//     %s %s\n' %
                       (os.path.basename(__file__), os.path.basename(file_path)))
diff --git a/media/webrtc/trunk/testing/gtest/scripts/upload.py b/media/webrtc/trunk/testing/gtest/scripts/upload.py
index 6e6f9a1471..5f55284505 100755
--- a/media/webrtc/trunk/testing/gtest/scripts/upload.py
+++ b/media/webrtc/trunk/testing/gtest/scripts/upload.py
@@ -31,7 +31,7 @@ against by using the '--rev' option.
 # This code is derived from appcfg.py in the App Engine SDK (open source),
 # and from ASPN recipe #146306.
 
-import cookielib
+import six.moves.http_cookiejar
 import getpass
 import logging
 import md5
@@ -42,9 +42,10 @@ import re
 import socket
 import subprocess
 import sys
-import urllib
-import urllib2
-import urlparse
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.parse
+import six
 
 try:
   import readline
@@ -75,19 +76,19 @@ def GetEmail(prompt):
   last_email = ""
   if os.path.exists(last_email_file_name):
     try:
-      last_email_file = open(last_email_file_name, "r")
+      last_email_file = open(last_email_file_name)
       last_email = last_email_file.readline().strip("\n")
       last_email_file.close()
       prompt += " [%s]" % last_email
-    except IOError, e:
+    except OSError as e:
       pass
-  email = raw_input(prompt + ": ").strip()
+  email = input(prompt + ": ").strip()
   if email:
     try:
       last_email_file = open(last_email_file_name, "w")
       last_email_file.write(email)
       last_email_file.close()
-    except IOError, e:
+    except OSError as e:
       pass
   else:
     email = last_email
@@ -103,25 +104,25 @@ def StatusUpdate(msg):
     msg: The string to print.
   """
   if verbosity > 0:
-    print msg
+    print(msg)
 
 
 def ErrorExit(msg):
   """Print an error message to stderr and exit."""
-  print >>sys.stderr, msg
+  print(msg, file=sys.stderr)
   sys.exit(1)
 
 
-class ClientLoginError(urllib2.HTTPError):
+class ClientLoginError(six.moves.urllib.error.HTTPError):
   """Raised to indicate there was an error authenticating with ClientLogin."""
 
   def __init__(self, url, code, msg, headers, args):
-    urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
+    six.moves.urllib.error.HTTPError.__init__(self, url, code, msg, headers, None)
     self.args = args
     self.reason = args["Error"]
 
 
-class AbstractRpcServer(object):
+class AbstractRpcServer:
   """Provides a common interface for a simple RPC server."""
 
   def __init__(self, host, auth_function, host_override=None, extra_headers={},
@@ -162,10 +163,10 @@ class AbstractRpcServer(object):
   def _CreateRequest(self, url, data=None):
     """Creates a new urllib request."""
     logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
-    req = urllib2.Request(url, data=data)
+    req = six.moves.urllib.request.Request(url, data=data)
     if self.host_override:
       req.add_header("Host", self.host_override)
-    for key, value in self.extra_headers.iteritems():
+    for key, value in self.extra_headers.items():
       req.add_header(key, value)
     return req
 
@@ -189,7 +190,7 @@ class AbstractRpcServer(object):
       account_type = "HOSTED"
     req = self._CreateRequest(
         url="https://www.google.com/accounts/ClientLogin",
-        data=urllib.urlencode({
+        data=six.moves.urllib.parse.urlencode({
             "Email": email,
             "Passwd": password,
             "service": "ah",
@@ -203,7 +204,7 @@ class AbstractRpcServer(object):
       response_dict = dict(x.split("=")
                            for x in response_body.split("\n") if x)
       return response_dict["Auth"]
-    except urllib2.HTTPError, e:
+    except six.moves.urllib.error.HTTPError as e:
       if e.code == 403:
         body = e.read()
         response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
@@ -225,14 +226,14 @@ class AbstractRpcServer(object):
     continue_location = "http://localhost/"
     args = {"continue": continue_location, "auth": auth_token}
     req = self._CreateRequest("http://%s/_ah/login?%s" %
-                              (self.host, urllib.urlencode(args)))
+                              (self.host, six.moves.urllib.parse.urlencode(args)))
     try:
       response = self.opener.open(req)
-    except urllib2.HTTPError, e:
+    except six.moves.urllib.error.HTTPError as e:
       response = e
     if (response.code != 302 or
         response.info()["location"] != continue_location):
-      raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
+      raise six.moves.urllib.error.HTTPError(req.get_full_url(), response.code, response.msg,
                               response.headers, response.fp)
     self.authenticated = True
 
@@ -255,34 +256,34 @@ class AbstractRpcServer(object):
       credentials = self.auth_function()
       try:
         auth_token = self._GetAuthToken(credentials[0], credentials[1])
-      except ClientLoginError, e:
+      except ClientLoginError as e:
         if e.reason == "BadAuthentication":
-          print >>sys.stderr, "Invalid username or password."
+          print("Invalid username or password.", file=sys.stderr)
           continue
         if e.reason == "CaptchaRequired":
-          print >>sys.stderr, (
+          print((
               "Please go to\n"
               "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
-              "and verify you are a human.  Then try again.")
+              "and verify you are a human.  Then try again."), file=sys.stderr)
           break
         if e.reason == "NotVerified":
-          print >>sys.stderr, "Account not verified."
+          print("Account not verified.", file=sys.stderr)
           break
         if e.reason == "TermsNotAgreed":
-          print >>sys.stderr, "User has not agreed to TOS."
+          print("User has not agreed to TOS.", file=sys.stderr)
           break
         if e.reason == "AccountDeleted":
-          print >>sys.stderr, "The user account has been deleted."
+          print("The user account has been deleted.", file=sys.stderr)
           break
         if e.reason == "AccountDisabled":
-          print >>sys.stderr, "The user account has been disabled."
+          print("The user account has been disabled.", file=sys.stderr)
           break
         if e.reason == "ServiceDisabled":
-          print >>sys.stderr, ("The user's access to the service has been "
-                               "disabled.")
+          print(("The user's access to the service has been "
+                               "disabled."), file=sys.stderr)
           break
         if e.reason == "ServiceUnavailable":
-          print >>sys.stderr, "The service is not available; try again later."
+          print("The service is not available; try again later.", file=sys.stderr)
           break
         raise
       self._GetAuthCookie(auth_token)
@@ -317,9 +318,9 @@ class AbstractRpcServer(object):
       while True:
         tries += 1
         args = dict(kwargs)
-        url = "http://%s%s" % (self.host, request_path)
+        url = "http://{}{}".format(self.host, request_path)
         if args:
-          url += "?" + urllib.urlencode(args)
+          url += "?" + six.moves.urllib.parse.urlencode(args)
         req = self._CreateRequest(url=url, data=payload)
         req.add_header("Content-Type", content_type)
         try:
@@ -327,7 +328,7 @@ class AbstractRpcServer(object):
           response = f.read()
           f.close()
           return response
-        except urllib2.HTTPError, e:
+        except six.moves.urllib.error.HTTPError as e:
           if tries > 3:
             raise
           elif e.code == 401:
@@ -346,7 +347,7 @@ class HttpRpcServer(AbstractRpcServer):
 
   def _Authenticate(self):
     """Save the cookie jar after authentication."""
-    super(HttpRpcServer, self)._Authenticate()
+    super()._Authenticate()
     if self.save_cookies:
       StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
       self.cookie_jar.save()
@@ -357,35 +358,35 @@ class HttpRpcServer(AbstractRpcServer):
     Returns:
       A urllib2.OpenerDirector object.
     """
-    opener = urllib2.OpenerDirector()
-    opener.add_handler(urllib2.ProxyHandler())
-    opener.add_handler(urllib2.UnknownHandler())
-    opener.add_handler(urllib2.HTTPHandler())
-    opener.add_handler(urllib2.HTTPDefaultErrorHandler())
-    opener.add_handler(urllib2.HTTPSHandler())
+    opener = six.moves.urllib.request.OpenerDirector()
+    opener.add_handler(six.moves.urllib.request.ProxyHandler())
+    opener.add_handler(six.moves.urllib.request.UnknownHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPDefaultErrorHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPSHandler())
     opener.add_handler(urllib2.HTTPErrorProcessor())
     if self.save_cookies:
       self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
-      self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
+      self.cookie_jar = six.moves.http_cookiejar.MozillaCookieJar(self.cookie_file)
       if os.path.exists(self.cookie_file):
         try:
           self.cookie_jar.load()
           self.authenticated = True
           StatusUpdate("Loaded authentication cookies from %s" %
                        self.cookie_file)
-        except (cookielib.LoadError, IOError):
+        except (six.moves.http_cookiejar.LoadError, OSError):
           # Failed to load cookies - just ignore them.
           pass
       else:
         # Create an empty cookie file with mode 600
-        fd = os.open(self.cookie_file, os.O_CREAT, 0600)
+        fd = os.open(self.cookie_file, os.O_CREAT, 0o600)
         os.close(fd)
       # Always chmod the cookie file
-      os.chmod(self.cookie_file, 0600)
+      os.chmod(self.cookie_file, 0o600)
     else:
       # Don't save cookies across runs of update.py.
-      self.cookie_jar = cookielib.CookieJar()
-    opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
+      self.cookie_jar = six.moves.http_cookiejar.CookieJar()
+    opener.add_handler(six.moves.urllib.request.HTTPCookieProcessor(self.cookie_jar))
     return opener
 
 
@@ -560,7 +561,7 @@ def RunShellWithReturnCode(command, print_output=False,
       line = p.stdout.readline()
       if not line:
         break
-      print line.strip("\n")
+      print(line.strip("\n"))
       output_array.append(line)
     output = "".join(output_array)
   else:
@@ -568,7 +569,7 @@ def RunShellWithReturnCode(command, print_output=False,
   p.wait()
   errout = p.stderr.read()
   if print_output and errout:
-    print >>sys.stderr, errout
+    print(errout, file=sys.stderr)
   p.stdout.close()
   p.stderr.close()
   return output, p.returncode
@@ -579,13 +580,13 @@ def RunShell(command, silent_ok=False, universal_newlines=True,
   data, retcode = RunShellWithReturnCode(command, print_output,
                                          universal_newlines)
   if retcode:
-    ErrorExit("Got error status from %s:\n%s" % (command, data))
+    ErrorExit("Got error status from {}:\n{}".format(command, data))
   if not silent_ok and not data:
     ErrorExit("No output from %s" % command)
   return data
 
 
-class VersionControlSystem(object):
+class VersionControlSystem:
   """Abstract base class providing an interface to the VCS."""
 
   def __init__(self, options):
@@ -614,11 +615,11 @@ class VersionControlSystem(object):
     """Show an "are you sure?" prompt if there are unknown files."""
     unknown_files = self.GetUnknownFiles()
     if unknown_files:
-      print "The following files are not added to version control:"
+      print("The following files are not added to version control:")
       for line in unknown_files:
-        print line
+        print(line)
       prompt = "Are you sure to continue?(y/N) "
-      answer = raw_input(prompt).strip()
+      answer = input(prompt).strip()
       if answer != "y":
         ErrorExit("User aborted")
 
@@ -670,13 +671,13 @@ class VersionControlSystem(object):
       else:
         type = "current"
       if len(content) > MAX_UPLOAD_SIZE:
-        print ("Not uploading the %s file for %s because it's too large." %
+        print("Not uploading the %s file for %s because it's too large." %
                (type, filename))
         file_too_large = True
         content = ""
       checksum = md5.new(content).hexdigest()
       if options.verbose > 0 and not file_too_large:
-        print "Uploading %s file for %s" % (type, filename)
+        print("Uploading {} file for {}".format(type, filename))
       url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
       form_fields = [("filename", filename),
                      ("status", status),
@@ -722,7 +723,7 @@ class SubversionVCS(VersionControlSystem):
   """Implementation of the VersionControlSystem interface for Subversion."""
 
   def __init__(self, options):
-    super(SubversionVCS, self).__init__(options)
+    super().__init__(options)
     if self.options.revision:
       match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
       if not match:
@@ -755,8 +756,8 @@ class SubversionVCS(VersionControlSystem):
       words = line.split()
       if len(words) == 2 and words[0] == "URL:":
         url = words[1]
-        scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
-        username, netloc = urllib.splituser(netloc)
+        scheme, netloc, path, params, query, fragment = six.moves.urllib.parse.urlparse(url)
+        username, netloc = six.moves.urllib.parse.splituser(netloc)
         if username:
           logging.info("Removed username from base URL")
         if netloc.endswith("svn.python.org"):
@@ -774,12 +775,12 @@ class SubversionVCS(VersionControlSystem):
           logging.info("Guessed CollabNet base = %s", base)
         elif netloc.endswith(".googlecode.com"):
           path = path + "/"
-          base = urlparse.urlunparse(("http", netloc, path, params,
+          base = six.moves.urllib.parse.urlunparse(("http", netloc, path, params,
                                       query, fragment))
           logging.info("Guessed Google Code base = %s", base)
         else:
           path = path + "/"
-          base = urlparse.urlunparse((scheme, netloc, path, params,
+          base = six.moves.urllib.parse.urlunparse((scheme, netloc, path, params,
                                       query, fragment))
           logging.info("Guessed base = %s", base)
         return base
@@ -826,7 +827,7 @@ class SubversionVCS(VersionControlSystem):
 
     def repl(m):
        if m.group(2):
-         return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
+         return "${}::{}$".format(m.group(1), " " * len(m.group(3)))
        return "$%s$" % m.group(1)
     keywords = [keyword
                 for name in keyword_str.split(" ")
@@ -918,7 +919,7 @@ class SubversionVCS(VersionControlSystem):
           (status[0] == " " and status[1] == "M")):  # Property change.
       args = []
       if self.options.revision:
-        url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+        url = "{}/{}@{}".format(self.svn_base, filename, self.rev_start)
       else:
         # Don't change filename, it's needed later.
         url = filename
@@ -941,7 +942,7 @@ class SubversionVCS(VersionControlSystem):
             if not self.rev_end:
               new_content = self.ReadFile(filename)
             else:
-              url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
+              url = "{}/{}@{}".format(self.svn_base, filename, self.rev_end)
               new_content = RunShell(["svn", "cat", url],
                                      universal_newlines=True, silent_ok=True)
         else:
@@ -957,7 +958,7 @@ class SubversionVCS(VersionControlSystem):
         if self.rev_start:
           # "svn cat -r REV delete_file.txt" doesn't work. cat requires
           # the full URL with "@REV" appended instead of using "-r" option.
-          url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+          url = "{}/{}@{}".format(self.svn_base, filename, self.rev_start)
           base_content = RunShell(["svn", "cat", url],
                                   universal_newlines=universal_newlines,
                                   silent_ok=True)
@@ -968,7 +969,7 @@ class SubversionVCS(VersionControlSystem):
         if not is_binary:
           args = []
           if self.rev_start:
-            url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+            url = "{}/{}@{}".format(self.svn_base, filename, self.rev_start)
           else:
             url = filename
             args += ["-r", "BASE"]
@@ -986,7 +987,7 @@ class GitVCS(VersionControlSystem):
   """Implementation of the VersionControlSystem interface for Git."""
 
   def __init__(self, options):
-    super(GitVCS, self).__init__(options)
+    super().__init__(options)
     # Map of filename -> hash of base file.
     self.base_hashes = {}
 
@@ -1043,7 +1044,7 @@ class MercurialVCS(VersionControlSystem):
   """Implementation of the VersionControlSystem interface for Mercurial."""
 
   def __init__(self, options, repo_dir):
-    super(MercurialVCS, self).__init__(options)
+    super().__init__(options)
     # Absolute path to repository (we can be in a subdir)
     self.repo_dir = os.path.normpath(repo_dir)
     # Compute the subdir
@@ -1069,7 +1070,7 @@ class MercurialVCS(VersionControlSystem):
     svndiff = []
     filecount = 0
     for line in data.splitlines():
-      m = re.match("diff --git a/(\S+) b/(\S+)", line)
+      m = re.match(r"diff --git a/(\S+) b/(\S+)", line)
       if m:
         # Modify line to make it look like as it comes from svn diff.
         # With this modification no changes on the server side are required
@@ -1187,7 +1188,7 @@ def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
   rv = []
   for patch in patches:
     if len(patch[1]) > MAX_UPLOAD_SIZE:
-      print ("Not uploading the patch for " + patch[0] +
+      print("Not uploading the patch for " + patch[0] +
              " because the file is too large.")
       continue
     form_fields = [("filename", patch[0])]
@@ -1196,7 +1197,7 @@ def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
     files = [("data", "data.diff", patch[1])]
     ctype, body = EncodeMultipartFormData(form_fields, files)
     url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
-    print "Uploading patch for " + patch[0]
+    print("Uploading patch for " + patch[0])
     response_body = rpc_server.Send(url, body, content_type=ctype)
     lines = response_body.splitlines()
     if not lines or lines[0] != "OK":
@@ -1223,7 +1224,8 @@ def GuessVCS(options):
     out, returncode = RunShellWithReturnCode(["hg", "root"])
     if returncode == 0:
       return MercurialVCS(options, out.strip())
-  except OSError, (errno, message):
+  except OSError as xxx_todo_changeme:
+    (errno, message) = xxx_todo_changeme.args
     if errno != 2:  # ENOENT -- they don't have hg installed.
       raise
 
@@ -1239,12 +1241,13 @@ def GuessVCS(options):
                                               "--is-inside-work-tree"])
     if returncode == 0:
       return GitVCS(options)
-  except OSError, (errno, message):
+  except OSError as xxx_todo_changeme1:
+    (errno, message) = xxx_todo_changeme1.args
     if errno != 2:  # ENOENT -- they don't have git installed.
       raise
 
-  ErrorExit(("Could not guess version control system. "
-             "Are you in a working copy directory?"))
+  ErrorExit("Could not guess version control system. "
+             "Are you in a working copy directory?")
 
 
 def RealMain(argv, data=None):
@@ -1286,12 +1289,12 @@ def RealMain(argv, data=None):
     data = vcs.GenerateDiff(args)
   files = vcs.GetBaseFiles(data)
   if verbosity >= 1:
-    print "Upload server:", options.server, "(change with -s/--server)"
+    print("Upload server:", options.server, "(change with -s/--server)")
   if options.issue:
     prompt = "Message describing this patch set: "
   else:
     prompt = "New issue subject: "
-  message = options.message or raw_input(prompt).strip()
+  message = options.message or input(prompt).strip()
   if not message:
     ErrorExit("A non-empty message is required")
   rpc_server = GetRpcServer(options)
@@ -1316,7 +1319,7 @@ def RealMain(argv, data=None):
   if options.description_file:
     if options.description:
       ErrorExit("Can't specify description and description_file")
-    file = open(options.description_file, 'r')
+    file = open(options.description_file)
     description = file.read()
     file.close()
   if description:
@@ -1324,7 +1327,7 @@ def RealMain(argv, data=None):
   # Send a hash of all the base file so the server can determine if a copy
   # already exists in an earlier patchset.
   base_hashes = ""
-  for file, info in files.iteritems():
+  for file, info in files.items():
     if not info[0] is None:
       checksum = md5.new(info[0]).hexdigest()
       if base_hashes:
@@ -1338,7 +1341,7 @@ def RealMain(argv, data=None):
   if not options.download_base:
     form_fields.append(("content_upload", "1"))
   if len(data) > MAX_UPLOAD_SIZE:
-    print "Patch is large, so uploading file patches separately."
+    print("Patch is large, so uploading file patches separately.")
     uploaded_diff_file = []
     form_fields.append(("separate_patches", "1"))
   else:
@@ -1378,7 +1381,7 @@ def main():
   try:
     RealMain(sys.argv)
   except KeyboardInterrupt:
-    print
+    print()
     StatusUpdate("Interrupted.")
     sys.exit(1)
 
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_break_on_failure_unittest.py b/media/webrtc/trunk/testing/gtest/test/gtest_break_on_failure_unittest.py
index c819183312..f36abe3381 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_break_on_failure_unittest.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_break_on_failure_unittest.py
@@ -145,7 +145,7 @@ class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase):
     msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' %
            (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command),
             should_or_not))
-    self.assert_(has_seg_fault == expect_seg_fault, msg)
+    self.assertTrue(has_seg_fault == expect_seg_fault, msg)
 
   def testDefaultBehavior(self):
     """Tests the behavior of the default mode."""
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_catch_exceptions_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_catch_exceptions_test.py
index d7ef10eb06..2269adc55b 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_catch_exceptions_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_catch_exceptions_test.py
@@ -74,21 +74,21 @@ if SUPPORTS_SEH_EXCEPTIONS:
 
 
     def TestSehExceptions(self, test_output):
-      self.assert_('SEH exception with code 0x2a thrown '
+      self.assertTrue('SEH exception with code 0x2a thrown '
                    'in the test fixture\'s constructor'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown '
+      self.assertTrue('SEH exception with code 0x2a thrown '
                    'in the test fixture\'s destructor'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()'
+      self.assertTrue('SEH exception with code 0x2a thrown in SetUpTestCase()'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()'
+      self.assertTrue('SEH exception with code 0x2a thrown in TearDownTestCase()'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown in SetUp()'
+      self.assertTrue('SEH exception with code 0x2a thrown in SetUp()'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown in TearDown()'
+      self.assertTrue('SEH exception with code 0x2a thrown in TearDown()'
                    in test_output)
-      self.assert_('SEH exception with code 0x2a thrown in the test body'
+      self.assertTrue('SEH exception with code 0x2a thrown in the test body'
                    in test_output)
 
     def testCatchesSehExceptionsWithCxxExceptionsEnabled(self):
@@ -108,11 +108,11 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
   """
 
   def testCatchesCxxExceptionsInFixtureConstructor(self):
-    self.assert_('C++ exception with description '
+    self.assertTrue('C++ exception with description '
                  '"Standard C++ exception" thrown '
                  'in the test fixture\'s constructor'
                  in EX_BINARY_OUTPUT)
-    self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+    self.assertTrue('unexpected' not in EX_BINARY_OUTPUT,
                  'This failure belongs in this test only if '
                  '"CxxExceptionInConstructorTest" (no quotes) '
                  'appears on the same line as words "called unexpectedly"')
@@ -121,87 +121,87 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
       EX_BINARY_OUTPUT):
 
     def testCatchesCxxExceptionsInFixtureDestructor(self):
-      self.assert_('C++ exception with description '
+      self.assertTrue('C++ exception with description '
                    '"Standard C++ exception" thrown '
                    'in the test fixture\'s destructor'
                    in EX_BINARY_OUTPUT)
-      self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() '
+      self.assertTrue('CxxExceptionInDestructorTest::TearDownTestCase() '
                    'called as expected.'
                    in EX_BINARY_OUTPUT)
 
   def testCatchesCxxExceptionsInSetUpTestCase(self):
-    self.assert_('C++ exception with description "Standard C++ exception"'
+    self.assertTrue('C++ exception with description "Standard C++ exception"'
                  ' thrown in SetUpTestCase()'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() '
+    self.assertTrue('CxxExceptionInConstructorTest::TearDownTestCase() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTestCaseTest constructor '
+    self.assertTrue('CxxExceptionInSetUpTestCaseTest constructor '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTestCaseTest destructor '
+    self.assertTrue('CxxExceptionInSetUpTestCaseTest destructor '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() '
+    self.assertTrue('CxxExceptionInSetUpTestCaseTest::SetUp() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() '
+    self.assertTrue('CxxExceptionInSetUpTestCaseTest::TearDown() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTestCaseTest test body '
+    self.assertTrue('CxxExceptionInSetUpTestCaseTest test body '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
 
   def testCatchesCxxExceptionsInTearDownTestCase(self):
-    self.assert_('C++ exception with description "Standard C++ exception"'
+    self.assertTrue('C++ exception with description "Standard C++ exception"'
                  ' thrown in TearDownTestCase()'
                  in EX_BINARY_OUTPUT)
 
   def testCatchesCxxExceptionsInSetUp(self):
-    self.assert_('C++ exception with description "Standard C++ exception"'
+    self.assertTrue('C++ exception with description "Standard C++ exception"'
                  ' thrown in SetUp()'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() '
+    self.assertTrue('CxxExceptionInSetUpTest::TearDownTestCase() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTest destructor '
+    self.assertTrue('CxxExceptionInSetUpTest destructor '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInSetUpTest::TearDown() '
+    self.assertTrue('CxxExceptionInSetUpTest::TearDown() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+    self.assertTrue('unexpected' not in EX_BINARY_OUTPUT,
                  'This failure belongs in this test only if '
                  '"CxxExceptionInSetUpTest" (no quotes) '
                  'appears on the same line as words "called unexpectedly"')
 
   def testCatchesCxxExceptionsInTearDown(self):
-    self.assert_('C++ exception with description "Standard C++ exception"'
+    self.assertTrue('C++ exception with description "Standard C++ exception"'
                  ' thrown in TearDown()'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() '
+    self.assertTrue('CxxExceptionInTearDownTest::TearDownTestCase() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInTearDownTest destructor '
+    self.assertTrue('CxxExceptionInTearDownTest destructor '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
 
   def testCatchesCxxExceptionsInTestBody(self):
-    self.assert_('C++ exception with description "Standard C++ exception"'
+    self.assertTrue('C++ exception with description "Standard C++ exception"'
                  ' thrown in the test body'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() '
+    self.assertTrue('CxxExceptionInTestBodyTest::TearDownTestCase() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInTestBodyTest destructor '
+    self.assertTrue('CxxExceptionInTestBodyTest destructor '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
-    self.assert_('CxxExceptionInTestBodyTest::TearDown() '
+    self.assertTrue('CxxExceptionInTestBodyTest::TearDown() '
                  'called as expected.'
                  in EX_BINARY_OUTPUT)
 
   def testCatchesNonStdCxxExceptions(self):
-    self.assert_('Unknown C++ exception thrown in the test body'
+    self.assertTrue('Unknown C++ exception thrown in the test body'
                  in EX_BINARY_OUTPUT)
 
   def testUnhandledCxxExceptionsAbortTheProgram(self):
@@ -214,9 +214,9 @@ class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
          NO_CATCH_EXCEPTIONS_FLAG,
          FITLER_OUT_SEH_TESTS_FLAG]).output
 
-    self.assert_('Unhandled C++ exception terminating the program'
+    self.assertTrue('Unhandled C++ exception terminating the program'
                  in uncaught_exceptions_ex_binary_output)
-    self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output)
+    self.assertTrue('unexpected' not in uncaught_exceptions_ex_binary_output)
 
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_color_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_color_test.py
index d02a53ed85..40e2e66eee 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_color_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_color_test.py
@@ -62,7 +62,7 @@ def UsesColor(term, color_env_var, color_flag):
   if color_flag is None:
     args = []
   else:
-    args = ['--%s=%s' % (COLOR_FLAG, color_flag)]
+    args = ['--{}={}'.format(COLOR_FLAG, color_flag)]
   p = gtest_test_utils.Subprocess([COMMAND] + args)
   return not p.exited or p.exit_code
 
@@ -72,58 +72,58 @@ class GTestColorTest(gtest_test_utils.TestCase):
     """Tests the case when there's neither GTEST_COLOR nor --gtest_color."""
 
     if not IS_WINDOWS:
-      self.assert_(not UsesColor('dumb', None, None))
-      self.assert_(not UsesColor('emacs', None, None))
-      self.assert_(not UsesColor('xterm-mono', None, None))
-      self.assert_(not UsesColor('unknown', None, None))
-      self.assert_(not UsesColor(None, None, None))
-    self.assert_(UsesColor('linux', None, None))
-    self.assert_(UsesColor('cygwin', None, None))
-    self.assert_(UsesColor('xterm', None, None))
-    self.assert_(UsesColor('xterm-color', None, None))
-    self.assert_(UsesColor('xterm-256color', None, None))
+      self.assertTrue(not UsesColor('dumb', None, None))
+      self.assertTrue(not UsesColor('emacs', None, None))
+      self.assertTrue(not UsesColor('xterm-mono', None, None))
+      self.assertTrue(not UsesColor('unknown', None, None))
+      self.assertTrue(not UsesColor(None, None, None))
+    self.assertTrue(UsesColor('linux', None, None))
+    self.assertTrue(UsesColor('cygwin', None, None))
+    self.assertTrue(UsesColor('xterm', None, None))
+    self.assertTrue(UsesColor('xterm-color', None, None))
+    self.assertTrue(UsesColor('xterm-256color', None, None))
 
   def testFlagOnly(self):
     """Tests the case when there's --gtest_color but not GTEST_COLOR."""
 
-    self.assert_(not UsesColor('dumb', None, 'no'))
-    self.assert_(not UsesColor('xterm-color', None, 'no'))
+    self.assertTrue(not UsesColor('dumb', None, 'no'))
+    self.assertTrue(not UsesColor('xterm-color', None, 'no'))
     if not IS_WINDOWS:
-      self.assert_(not UsesColor('emacs', None, 'auto'))
-    self.assert_(UsesColor('xterm', None, 'auto'))
-    self.assert_(UsesColor('dumb', None, 'yes'))
-    self.assert_(UsesColor('xterm', None, 'yes'))
+      self.assertTrue(not UsesColor('emacs', None, 'auto'))
+    self.assertTrue(UsesColor('xterm', None, 'auto'))
+    self.assertTrue(UsesColor('dumb', None, 'yes'))
+    self.assertTrue(UsesColor('xterm', None, 'yes'))
 
   def testEnvVarOnly(self):
     """Tests the case when there's GTEST_COLOR but not --gtest_color."""
 
-    self.assert_(not UsesColor('dumb', 'no', None))
-    self.assert_(not UsesColor('xterm-color', 'no', None))
+    self.assertTrue(not UsesColor('dumb', 'no', None))
+    self.assertTrue(not UsesColor('xterm-color', 'no', None))
     if not IS_WINDOWS:
-      self.assert_(not UsesColor('dumb', 'auto', None))
-    self.assert_(UsesColor('xterm-color', 'auto', None))
-    self.assert_(UsesColor('dumb', 'yes', None))
-    self.assert_(UsesColor('xterm-color', 'yes', None))
+      self.assertTrue(not UsesColor('dumb', 'auto', None))
+    self.assertTrue(UsesColor('xterm-color', 'auto', None))
+    self.assertTrue(UsesColor('dumb', 'yes', None))
+    self.assertTrue(UsesColor('xterm-color', 'yes', None))
 
   def testEnvVarAndFlag(self):
     """Tests the case when there are both GTEST_COLOR and --gtest_color."""
 
-    self.assert_(not UsesColor('xterm-color', 'no', 'no'))
-    self.assert_(UsesColor('dumb', 'no', 'yes'))
-    self.assert_(UsesColor('xterm-color', 'no', 'auto'))
+    self.assertTrue(not UsesColor('xterm-color', 'no', 'no'))
+    self.assertTrue(UsesColor('dumb', 'no', 'yes'))
+    self.assertTrue(UsesColor('xterm-color', 'no', 'auto'))
 
   def testAliasesOfYesAndNo(self):
     """Tests using aliases in specifying --gtest_color."""
 
-    self.assert_(UsesColor('dumb', None, 'true'))
-    self.assert_(UsesColor('dumb', None, 'YES'))
-    self.assert_(UsesColor('dumb', None, 'T'))
-    self.assert_(UsesColor('dumb', None, '1'))
+    self.assertTrue(UsesColor('dumb', None, 'true'))
+    self.assertTrue(UsesColor('dumb', None, 'YES'))
+    self.assertTrue(UsesColor('dumb', None, 'T'))
+    self.assertTrue(UsesColor('dumb', None, '1'))
 
-    self.assert_(not UsesColor('xterm', None, 'f'))
-    self.assert_(not UsesColor('xterm', None, 'false'))
-    self.assert_(not UsesColor('xterm', None, '0'))
-    self.assert_(not UsesColor('xterm', None, 'unknown'))
+    self.assertTrue(not UsesColor('xterm', None, 'f'))
+    self.assertTrue(not UsesColor('xterm', None, 'false'))
+    self.assertTrue(not UsesColor('xterm', None, '0'))
+    self.assertTrue(not UsesColor('xterm', None, 'unknown'))
 
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_env_var_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_env_var_test.py
index 4728bbc316..4e1c77fc2e 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_env_var_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_env_var_test.py
@@ -47,8 +47,8 @@ environ = os.environ.copy()
 
 def AssertEq(expected, actual):
   if expected != actual:
-    print 'Expected: %s' % (expected,)
-    print '  Actual: %s' % (actual,)
+    print('Expected: {}'.format(expected))
+    print('  Actual: {}'.format(actual))
     raise AssertionError
 
 
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_filter_unittest.py b/media/webrtc/trunk/testing/gtest/test/gtest_filter_unittest.py
index 0d1a770058..df0165cd84 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_filter_unittest.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_filter_unittest.py
@@ -231,10 +231,10 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
     """Asserts that two sets are equal."""
 
     for elem in lhs:
-      self.assert_(elem in rhs, '%s in %s' % (elem, rhs))
+      self.assertTrue(elem in rhs, '{} in {}'.format(elem, rhs))
 
     for elem in rhs:
-      self.assert_(elem in lhs, '%s in %s' % (elem, lhs))
+      self.assertTrue(elem in lhs, '{} in {}'.format(elem, lhs))
 
   def AssertPartitionIsValid(self, set_var, list_of_sets):
     """Asserts that list_of_sets is a valid partition of set_var."""
@@ -279,7 +279,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
     if gtest_filter is None:
       args = []
     else:
-      args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)]
+      args = ['--{}={}'.format(FILTER_FLAG, gtest_filter)]
 
     tests_run = RunAndExtractTestList(args)[0]
     self.AssertSetEqual(tests_run, tests_to_run)
@@ -338,7 +338,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
     # Construct the command line.
     args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG]
     if gtest_filter is not None:
-      args.append('--%s=%s' % (FILTER_FLAG, gtest_filter))
+      args.append('--{}={}'.format(FILTER_FLAG, gtest_filter))
 
     tests_run = RunAndExtractTestList(args)[0]
     self.AssertSetEqual(tests_run, tests_to_run)
@@ -564,7 +564,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
     """Tests that the filter flag overrides the filtering env. variable."""
 
     SetEnvVar(FILTER_ENV_VAR, 'Foo*')
-    args = ['--%s=%s' % (FILTER_FLAG, '*One')]
+    args = ['--{}={}'.format(FILTER_FLAG, '*One')]
     tests_run = RunAndExtractTestList(args)[0]
     SetEnvVar(FILTER_ENV_VAR, None)
 
@@ -575,13 +575,13 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
 
     shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
                                      'shard_status_file')
-    self.assert_(not os.path.exists(shard_status_file))
+    self.assertTrue(not os.path.exists(shard_status_file))
 
     extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
     try:
       InvokeWithModifiedEnv(extra_env, RunAndReturnOutput)
     finally:
-      self.assert_(os.path.exists(shard_status_file))
+      self.assertTrue(os.path.exists(shard_status_file))
       os.remove(shard_status_file)
 
   def testShardStatusFileIsCreatedWithListTests(self):
@@ -589,7 +589,7 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
 
     shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
                                      'shard_status_file2')
-    self.assert_(not os.path.exists(shard_status_file))
+    self.assertTrue(not os.path.exists(shard_status_file))
 
     extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
     try:
@@ -599,12 +599,12 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
     finally:
       # This assertion ensures that Google Test enumerated the tests as
       # opposed to running them.
-      self.assert_('[==========]' not in output,
+      self.assertTrue('[==========]' not in output,
                    'Unexpected output during test enumeration.\n'
                    'Please ensure that LIST_TESTS_FLAG is assigned the\n'
                    'correct flag value for listing Google Test tests.')
 
-      self.assert_(os.path.exists(shard_status_file))
+      self.assertTrue(os.path.exists(shard_status_file))
       os.remove(shard_status_file)
 
   if SUPPORTS_DEATH_TESTS:
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_help_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_help_test.py
index 093c838d9e..32ff46ca53 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_help_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_help_test.py
@@ -109,18 +109,18 @@ class GTestHelpTest(gtest_test_utils.TestCase):
     """
 
     exit_code, output = RunWithFlag(flag)
-    self.assertEquals(0, exit_code)
-    self.assert_(HELP_REGEX.search(output), output)
+    self.assertEqual(0, exit_code)
+    self.assertTrue(HELP_REGEX.search(output), output)
 
     if IS_LINUX:
-      self.assert_(STREAM_RESULT_TO_FLAG in output, output)
+      self.assertTrue(STREAM_RESULT_TO_FLAG in output, output)
     else:
-      self.assert_(STREAM_RESULT_TO_FLAG not in output, output)
+      self.assertTrue(STREAM_RESULT_TO_FLAG not in output, output)
 
     if SUPPORTS_DEATH_TESTS and not IS_WINDOWS:
-      self.assert_(DEATH_TEST_STYLE_FLAG in output, output)
+      self.assertTrue(DEATH_TEST_STYLE_FLAG in output, output)
     else:
-      self.assert_(DEATH_TEST_STYLE_FLAG not in output, output)
+      self.assertTrue(DEATH_TEST_STYLE_FLAG not in output, output)
 
   def TestNonHelpFlag(self, flag):
     """Verifies correct behavior when no help flag is specified.
@@ -133,8 +133,8 @@ class GTestHelpTest(gtest_test_utils.TestCase):
     """
 
     exit_code, output = RunWithFlag(flag)
-    self.assert_(exit_code != 0)
-    self.assert_(not HELP_REGEX.search(output), output)
+    self.assertTrue(exit_code != 0)
+    self.assertTrue(not HELP_REGEX.search(output), output)
 
   def testPrintsHelpWithFullFlag(self):
     self.TestHelpFlag('--help')
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_list_tests_unittest.py b/media/webrtc/trunk/testing/gtest/test/gtest_list_tests_unittest.py
index ce8c3ef05f..1d3ce746ca 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_list_tests_unittest.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_list_tests_unittest.py
@@ -136,9 +136,9 @@ class GTestListTestsUnitTest(gtest_test_utils.TestCase):
            (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output))
 
     if expected_output is not None:
-      self.assert_(output == expected_output, msg)
+      self.assertTrue(output == expected_output, msg)
     else:
-      self.assert_(output != EXPECTED_OUTPUT_NO_FILTER, msg)
+      self.assertTrue(output != EXPECTED_OUTPUT_NO_FILTER, msg)
 
   def testDefaultBehavior(self):
     """Tests the behavior of the default mode."""
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_output_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_output_test.py
index 72b3ae0084..9a684489df 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_output_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_output_test.py
@@ -141,7 +141,7 @@ def NormalizeToCurrentPlatform(test_output):
 
   if IS_WINDOWS:
     # Removes the color information that is not present on Windows.
-    test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output)
+    test_output = re.sub('\x1b\\[(0;3\\d)?m', '', test_output)
     # Changes failure message headers into the Windows format.
     test_output = re.sub(r': Failure\n', r': error: ', test_output)
     # Changes file(line_number) to file:line_number.
@@ -180,7 +180,7 @@ def RemoveMatchingTests(test_output, pattern):
   """
 
   test_output = re.sub(
-      r'.*\[ RUN      \] .*%s(.|\n)*?\[(  FAILED  |       OK )\] .*%s.*\n' % (
+      r'.*\[ RUN      \] .*{}(.|\n)*?\[(  FAILED  |       OK )\] .*{}.*\n'.format(
           pattern, pattern),
       '',
       test_output)
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_shuffle_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_shuffle_test.py
index d3e57809de..e084a335ab 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_shuffle_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_shuffle_test.py
@@ -60,11 +60,11 @@ def AlsoRunDisabledTestsFlag():
 
 
 def FilterFlag(test_filter):
-  return '--gtest_filter=%s' % (test_filter,)
+  return '--gtest_filter={}'.format(test_filter)
 
 
 def RepeatFlag(n):
-  return '--gtest_repeat=%s' % (n,)
+  return '--gtest_repeat={}'.format(n)
 
 
 def ShuffleFlag():
@@ -72,7 +72,7 @@ def ShuffleFlag():
 
 
 def RandomSeedFlag(n):
-  return '--gtest_random_seed=%s' % (n,)
+  return '--gtest_random_seed={}'.format(n)
 
 
 def RunAndReturnOutput(extra_env, args):
@@ -180,66 +180,66 @@ class GTestShuffleUnitTest(gtest_test_utils.TestCase):
     self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS))
 
   def testShuffleChangesTestOrder(self):
-    self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
-    self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
-    self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
+    self.assertTrue(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
+    self.assertTrue(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
+    self.assertTrue(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
                  SHUFFLED_FILTERED_TESTS)
-    self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
+    self.assertTrue(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
                  SHUFFLED_SHARDED_TESTS)
 
   def testShuffleChangesTestCaseOrder(self):
-    self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
+    self.assertTrue(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
                  GetTestCases(SHUFFLED_ALL_TESTS))
-    self.assert_(
+    self.assertTrue(
         GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS),
         GetTestCases(SHUFFLED_ACTIVE_TESTS))
-    self.assert_(
+    self.assertTrue(
         GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS),
         GetTestCases(SHUFFLED_FILTERED_TESTS))
-    self.assert_(
+    self.assertTrue(
         GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS),
         GetTestCases(SHUFFLED_SHARDED_TESTS))
 
   def testShuffleDoesNotRepeatTest(self):
     for test in SHUFFLED_ALL_TESTS:
       self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test),
-                       '%s appears more than once' % (test,))
+                       '{} appears more than once'.format(test))
     for test in SHUFFLED_ACTIVE_TESTS:
       self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test),
-                       '%s appears more than once' % (test,))
+                       '{} appears more than once'.format(test))
     for test in SHUFFLED_FILTERED_TESTS:
       self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test),
-                       '%s appears more than once' % (test,))
+                       '{} appears more than once'.format(test))
     for test in SHUFFLED_SHARDED_TESTS:
       self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test),
-                       '%s appears more than once' % (test,))
+                       '{} appears more than once'.format(test))
 
   def testShuffleDoesNotCreateNewTest(self):
     for test in SHUFFLED_ALL_TESTS:
-      self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,))
+      self.assertTrue(test in ALL_TESTS, '{} is an invalid test'.format(test))
     for test in SHUFFLED_ACTIVE_TESTS:
-      self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,))
+      self.assertTrue(test in ACTIVE_TESTS, '{} is an invalid test'.format(test))
     for test in SHUFFLED_FILTERED_TESTS:
-      self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,))
+      self.assertTrue(test in FILTERED_TESTS, '{} is an invalid test'.format(test))
     for test in SHUFFLED_SHARDED_TESTS:
-      self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,))
+      self.assertTrue(test in SHARDED_TESTS, '{} is an invalid test'.format(test))
 
   def testShuffleIncludesAllTests(self):
     for test in ALL_TESTS:
-      self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,))
+      self.assertTrue(test in SHUFFLED_ALL_TESTS, '{} is missing'.format(test))
     for test in ACTIVE_TESTS:
-      self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,))
+      self.assertTrue(test in SHUFFLED_ACTIVE_TESTS, '{} is missing'.format(test))
     for test in FILTERED_TESTS:
-      self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,))
+      self.assertTrue(test in SHUFFLED_FILTERED_TESTS, '{} is missing'.format(test))
     for test in SHARDED_TESTS:
-      self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,))
+      self.assertTrue(test in SHUFFLED_SHARDED_TESTS, '{} is missing'.format(test))
 
   def testShuffleLeavesDeathTestsAtFront(self):
     non_death_test_found = False
     for test in SHUFFLED_ACTIVE_TESTS:
       if 'DeathTest.' in test:
-        self.assert_(not non_death_test_found,
-                     '%s appears after a non-death test' % (test,))
+        self.assertTrue(not non_death_test_found,
+                     '{} appears after a non-death test'.format(test))
       else:
         non_death_test_found = True
 
@@ -296,11 +296,11 @@ class GTestShuffleUnitTest(gtest_test_utils.TestCase):
         GetTestsForAllIterations(
             {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
 
-    self.assert_(tests_in_iteration1 != tests_in_iteration2,
+    self.assertTrue(tests_in_iteration1 != tests_in_iteration2,
                  tests_in_iteration1)
-    self.assert_(tests_in_iteration1 != tests_in_iteration3,
+    self.assertTrue(tests_in_iteration1 != tests_in_iteration3,
                  tests_in_iteration1)
-    self.assert_(tests_in_iteration2 != tests_in_iteration3,
+    self.assertTrue(tests_in_iteration2 != tests_in_iteration3,
                  tests_in_iteration2)
 
   def testShuffleShardedTestsPreservesPartition(self):
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py b/media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py
index 6dd8db4bf0..39a6031cd5 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_test_utils.py
@@ -163,7 +163,7 @@ def GetTestExecutablePath(executable_name, build_dir=None):
         'Unable to find the test binary. Please make sure to provide path\n'
         'to the binary via the --build_dir flag or the BUILD_DIR\n'
         'environment variable.')
-    print >> sys.stderr, message
+    print(message, file=sys.stderr)
     sys.exit(1)
 
   return path
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_throw_on_failure_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_throw_on_failure_test.py
index 5678ffeaf6..318e6306c5 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_throw_on_failure_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_throw_on_failure_test.py
@@ -70,7 +70,7 @@ def SetEnvVar(env_var, value):
 def Run(command):
   """Runs a command; returns True/False if its exit code is/isn't 0."""
 
-  print 'Running "%s". . .' % ' '.join(command)
+  print('Running "%s". . .' % ' '.join(command))
   p = gtest_test_utils.Subprocess(command)
   return p.exited and p.exit_code == 0
 
@@ -123,7 +123,7 @@ class ThrowOnFailureTest(gtest_test_utils.TestCase):
            'exit code.' %
            (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command),
             should_or_not))
-    self.assert_(failed == should_fail, msg)
+    self.assertTrue(failed == should_fail, msg)
 
   def testDefaultBehavior(self):
     """Tests the behavior of the default mode."""
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_uninitialized_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_uninitialized_test.py
index 6ae57eeeda..9dd807df2a 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_uninitialized_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_uninitialized_test.py
@@ -46,8 +46,8 @@ def Assert(condition):
 
 def AssertEq(expected, actual):
   if expected != actual:
-    print 'Expected: %s' % (expected,)
-    print '  Actual: %s' % (actual,)
+    print('Expected: {}'.format(expected))
+    print('  Actual: {}'.format(actual))
     raise AssertionError
 
 
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_xml_outfiles_test.py b/media/webrtc/trunk/testing/gtest/test/gtest_xml_outfiles_test.py
index 524e437e6c..a36c552df2 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_xml_outfiles_test.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_xml_outfiles_test.py
@@ -78,15 +78,15 @@ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
   def DeleteFilesAndDir(self):
     try:
       os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml"))
-    except os.error:
+    except OSError:
       pass
     try:
       os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml"))
-    except os.error:
+    except OSError:
       pass
     try:
       os.rmdir(self.output_dir_)
-    except os.error:
+    except OSError:
       pass
 
   def testOutfile1(self):
@@ -100,8 +100,8 @@ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
     command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_]
     p = gtest_test_utils.Subprocess(command,
                                     working_dir=gtest_test_utils.GetTempDir())
-    self.assert_(p.exited)
-    self.assertEquals(0, p.exit_code)
+    self.assertTrue(p.exited)
+    self.assertEqual(0, p.exit_code)
 
     # TODO(wan@google.com): libtool causes the built test binary to be
     #   named lt-gtest_xml_outfiles_test_ instead of
@@ -112,7 +112,7 @@ class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
     output_file1 = os.path.join(self.output_dir_, output_file_name1)
     output_file_name2 = 'lt-' + output_file_name1
     output_file2 = os.path.join(self.output_dir_, output_file_name2)
-    self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2),
+    self.assertTrue(os.path.isfile(output_file1) or os.path.isfile(output_file2),
                  output_file1)
 
     expected = minidom.parseString(expected_xml)
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_xml_output_unittest.py b/media/webrtc/trunk/testing/gtest/test/gtest_xml_output_unittest.py
index 8cdfb56b68..8dcce1cffa 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_xml_output_unittest.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_xml_output_unittest.py
@@ -65,7 +65,7 @@ EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
     <testcase name="Fails" status="run" time="*" classname="FailedTest">
       <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
 Value of: 2
-Expected: 1%(stack)s]]></failure>
+Expected: 1{stack}]]></failure>
     </testcase>
   </testsuite>
   <testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
@@ -73,10 +73,10 @@ Expected: 1%(stack)s]]></failure>
     <testcase name="Fails" status="run" time="*" classname="MixedResultTest">
       <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
 Value of: 2
-Expected: 1%(stack)s]]></failure>
+Expected: 1{stack}]]></failure>
       <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Value of: 3&#x0A;Expected: 2" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
 Value of: 3
-Expected: 2%(stack)s]]></failure>
+Expected: 2{stack}]]></failure>
     </testcase>
     <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
   </testsuite>
@@ -84,14 +84,14 @@ Expected: 2%(stack)s]]></failure>
     <testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest">
       <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Failed&#x0A;XML output: &lt;?xml encoding=&quot;utf-8&quot;&gt;&lt;top&gt;&lt;![CDATA[cdata text]]&gt;&lt;/top&gt;" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
 Failed
-XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>%(stack)s]]></failure>
+XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>{stack}]]></failure>
     </testcase>
   </testsuite>
   <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*">
     <testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest">
       <failure message="gtest_xml_output_unittest_.cc:*&#x0A;Failed&#x0A;Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
 Failed
-Invalid characters in brackets []%(stack)s]]></failure>
+Invalid characters in brackets []{stack}]]></failure>
     </testcase>
   </testsuite>
   <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
@@ -126,7 +126,7 @@ Invalid characters in brackets []%(stack)s]]></failure>
   <testsuite name="Single/TypeParameterizedTestCase/1" tests="1" failures="0" disabled="0" errors="0" time="*">
     <testcase name="HasTypeParamAttribute" type_param="*" status="run" time="*" classname="Single/TypeParameterizedTestCase/1" />
   </testsuite>
-</testsuites>""" % {'stack': STACK_TRACE_TEMPLATE}
+</testsuites>""".format(stack=STACK_TRACE_TEMPLATE)
 
 
 EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
@@ -199,16 +199,16 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
         'gtest_no_test_unittest')
     try:
       os.remove(output_file)
-    except OSError, e:
+    except OSError as e:
       if e.errno != errno.ENOENT:
         raise
 
     p = gtest_test_utils.Subprocess(
         [gtest_prog_path, '%s=xml' % GTEST_OUTPUT_FLAG],
         working_dir=gtest_test_utils.GetTempDir())
-    self.assert_(p.exited)
-    self.assertEquals(0, p.exit_code)
-    self.assert_(os.path.isfile(output_file))
+    self.assertTrue(p.exited)
+    self.assertEqual(0, p.exit_code)
+    self.assertTrue(os.path.isfile(output_file))
 
   def testSuppressedXmlOutput(self):
     """
@@ -222,7 +222,7 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
       os.remove(xml_path)
 
     command = [GTEST_PROGRAM_PATH,
-               '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path),
+               '{}=xml:{}'.format(GTEST_OUTPUT_FLAG, xml_path),
                '--shut_down_xml']
     p = gtest_test_utils.Subprocess(command)
     if p.terminated_by_signal:
@@ -231,13 +231,13 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
           p.terminated_by_signal,
           '%s was killed by signal %d' % (GTEST_PROGRAM_NAME, p.signal))
     else:
-      self.assert_(p.exited)
-      self.assertEquals(1, p.exit_code,
+      self.assertTrue(p.exited)
+      self.assertEqual(1, p.exit_code,
                         "'%s' exited with code %s, which doesn't match "
                         'the expected exit code %s.'
                         % (command, p.exit_code, 1))
 
-    self.assert_(not os.path.isfile(xml_path))
+    self.assertTrue(not os.path.isfile(xml_path))
 
   def _GetXmlOutput(self, gtest_prog_name, expected_exit_code):
     """
@@ -248,14 +248,14 @@ class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
                             gtest_prog_name + 'out.xml')
     gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
 
-    command = [gtest_prog_path, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path)]
+    command = [gtest_prog_path, '{}=xml:{}'.format(GTEST_OUTPUT_FLAG, xml_path)]
     p = gtest_test_utils.Subprocess(command)
     if p.terminated_by_signal:
-      self.assert_(False,
+      self.assertTrue(False,
                    '%s was killed by signal %d' % (gtest_prog_name, p.signal))
     else:
-      self.assert_(p.exited)
-      self.assertEquals(expected_exit_code, p.exit_code,
+      self.assertTrue(p.exited)
+      self.assertEqual(expected_exit_code, p.exit_code,
                         "'%s' exited with code %s, which doesn't match "
                         'the expected exit code %s.'
                         % (command, p.exit_code, expected_exit_code))
diff --git a/media/webrtc/trunk/testing/gtest/test/gtest_xml_test_utils.py b/media/webrtc/trunk/testing/gtest/test/gtest_xml_test_utils.py
index 0e5a1089d1..1542337f6b 100755
--- a/media/webrtc/trunk/testing/gtest/test/gtest_xml_test_utils.py
+++ b/media/webrtc/trunk/testing/gtest/test/gtest_xml_test_utils.py
@@ -68,37 +68,37 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
     """
 
     if expected_node.nodeType == Node.CDATA_SECTION_NODE:
-      self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
-      self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
+      self.assertEqual(Node.CDATA_SECTION_NODE, actual_node.nodeType)
+      self.assertEqual(expected_node.nodeValue, actual_node.nodeValue)
       return
 
-    self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
-    self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
-    self.assertEquals(expected_node.tagName, actual_node.tagName)
+    self.assertEqual(Node.ELEMENT_NODE, actual_node.nodeType)
+    self.assertEqual(Node.ELEMENT_NODE, expected_node.nodeType)
+    self.assertEqual(expected_node.tagName, actual_node.tagName)
 
     expected_attributes = expected_node.attributes
     actual_attributes   = actual_node  .attributes
-    self.assertEquals(
+    self.assertEqual(
         expected_attributes.length, actual_attributes.length,
         'attribute numbers differ in element ' + actual_node.tagName)
     for i in range(expected_attributes.length):
       expected_attr = expected_attributes.item(i)
       actual_attr   = actual_attributes.get(expected_attr.name)
-      self.assert_(
+      self.assertTrue(
           actual_attr is not None,
           'expected attribute %s not found in element %s' %
           (expected_attr.name, actual_node.tagName))
-      self.assertEquals(expected_attr.value, actual_attr.value,
+      self.assertEqual(expected_attr.value, actual_attr.value,
                         ' values of attribute %s in element %s differ' %
                         (expected_attr.name, actual_node.tagName))
 
     expected_children = self._GetChildren(expected_node)
     actual_children = self._GetChildren(actual_node)
-    self.assertEquals(
+    self.assertEqual(
         len(expected_children), len(actual_children),
         'number of child elements differ in element ' + actual_node.tagName)
-    for child_id, child in expected_children.iteritems():
-      self.assert_(child_id in actual_children,
+    for child_id, child in expected_children.items():
+      self.assertTrue(child_id in actual_children,
                    '<%s> is not in <%s> (in element %s)' %
                    (child_id, actual_children, actual_node.tagName))
       self.AssertEquivalentNodes(child, actual_children[child_id])
@@ -126,10 +126,10 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
     children = {}
     for child in element.childNodes:
       if child.nodeType == Node.ELEMENT_NODE:
-        self.assert_(child.tagName in self.identifying_attribute,
+        self.assertTrue(child.tagName in self.identifying_attribute,
                      'Encountered unknown element <%s>' % child.tagName)
         childID = child.getAttribute(self.identifying_attribute[child.tagName])
-        self.assert_(childID not in children)
+        self.assertTrue(childID not in children)
         children[childID] = child
       elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
         if 'detail' not in children:
diff --git a/media/webrtc/trunk/testing/gtest/xcode/Scripts/versiongenerate.py b/media/webrtc/trunk/testing/gtest/xcode/Scripts/versiongenerate.py
index 81de8c96ac..edbbba669d 100644
--- a/media/webrtc/trunk/testing/gtest/xcode/Scripts/versiongenerate.py
+++ b/media/webrtc/trunk/testing/gtest/xcode/Scripts/versiongenerate.py
@@ -54,14 +54,14 @@ import re
 
 # Read the command line argument (the output directory for Version.h)
 if (len(sys.argv) < 3):
-  print "Usage: versiongenerate.py input_dir output_dir"
+  print("Usage: versiongenerate.py input_dir output_dir")
   sys.exit(1)
 else:
   input_dir = sys.argv[1]
   output_dir = sys.argv[2]
 
 # Read the first 1024 characters of the configure.ac file
-config_file = open("%s/configure.ac" % input_dir, 'r')
+config_file = open("%s/configure.ac" % input_dir)
 buffer_size = 1024
 opening_string = config_file.read(buffer_size)
 config_file.close()
@@ -91,10 +91,10 @@ file_data = """//
 // this, we are not not restricted to C-syntax nor are we using include guards.
 //
 
-#define GTEST_VERSIONINFO_SHORT %s.%s
-#define GTEST_VERSIONINFO_LONG %s.%s.%s
+#define GTEST_VERSIONINFO_SHORT {}.{}
+#define GTEST_VERSIONINFO_LONG {}.{}.{}
 
-""" % (major_version, minor_version, major_version, minor_version, fix_version)
+""".format(major_version, minor_version, major_version, minor_version, fix_version)
 version_file = open("%s/Version.h" % output_dir, 'w')
 version_file.write(file_data)
 version_file.close()
diff --git a/media/webrtc/trunk/tools/gyp/PRESUBMIT.py b/media/webrtc/trunk/tools/gyp/PRESUBMIT.py
index dde025383c..8180fe5f95 100644
--- a/media/webrtc/trunk/tools/gyp/PRESUBMIT.py
+++ b/media/webrtc/trunk/tools/gyp/PRESUBMIT.py
@@ -85,7 +85,7 @@ def CheckChangeOnCommit(input_api, output_api):
 
   # Accept any year number from 2009 to the current year.
   current_year = int(input_api.time.strftime('%Y'))
-  allowed_years = (str(s) for s in reversed(xrange(2009, current_year + 1)))
+  allowed_years = (str(s) for s in reversed(range(2009, current_year + 1)))
   years_re = '(' + '|'.join(allowed_years) + ')'
 
   # The (c) is deprecated, but tolerate it until it's removed from all files.
diff --git a/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py b/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py
index 9a2b71f1b3..964ed26bf0 100755
--- a/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py
+++ b/media/webrtc/trunk/tools/gyp/buildbot/buildbot_run.py
@@ -24,14 +24,14 @@ def CallSubProcess(*args, **kwargs):
   with open(os.devnull) as devnull_fd:
     retcode = subprocess.call(stdin=devnull_fd, *args, **kwargs)
   if retcode != 0:
-    print '@@@STEP_EXCEPTION@@@'
+    print('@@@STEP_EXCEPTION@@@')
     sys.exit(1)
 
 
 def PrepareCmake():
   """Build CMake 2.8.8 since the version in Precise is 2.8.7."""
   if os.environ['BUILDBOT_CLOBBER'] == '1':
-    print '@@@BUILD_STEP Clobber CMake checkout@@@'
+    print('@@@BUILD_STEP Clobber CMake checkout@@@')
     shutil.rmtree(CMAKE_DIR)
 
   # We always build CMake 2.8.8, so no need to do anything
@@ -39,10 +39,10 @@ def PrepareCmake():
   if os.path.isdir(CMAKE_DIR):
     return
 
-  print '@@@BUILD_STEP Initialize CMake checkout@@@'
+  print('@@@BUILD_STEP Initialize CMake checkout@@@')
   os.mkdir(CMAKE_DIR)
 
-  print '@@@BUILD_STEP Sync CMake@@@'
+  print('@@@BUILD_STEP Sync CMake@@@')
   CallSubProcess(
       ['git', 'clone',
        '--depth', '1',
@@ -53,7 +53,7 @@ def PrepareCmake():
        CMAKE_DIR],
       cwd=CMAKE_DIR)
 
-  print '@@@BUILD_STEP Build CMake@@@'
+  print('@@@BUILD_STEP Build CMake@@@')
   CallSubProcess(
       ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR],
       cwd=CMAKE_DIR)
@@ -74,7 +74,7 @@ def GypTestFormat(title, format=None, msvs_version=None, tests=[]):
   if not format:
     format = title
 
-  print '@@@BUILD_STEP ' + title + '@@@'
+  print('@@@BUILD_STEP ' + title + '@@@')
   sys.stdout.flush()
   env = os.environ.copy()
   if msvs_version:
@@ -89,17 +89,17 @@ def GypTestFormat(title, format=None, msvs_version=None, tests=[]):
   retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True)
   if retcode:
     # Emit failure tag, and keep going.
-    print '@@@STEP_FAILURE@@@'
+    print('@@@STEP_FAILURE@@@')
     return 1
   return 0
 
 
 def GypBuild():
   # Dump out/ directory.
-  print '@@@BUILD_STEP cleanup@@@'
-  print 'Removing %s...' % OUT_DIR
+  print('@@@BUILD_STEP cleanup@@@')
+  print('Removing %s...' % OUT_DIR)
   shutil.rmtree(OUT_DIR, ignore_errors=True)
-  print 'Done.'
+  print('Done.')
 
   retcode = 0
   if sys.platform.startswith('linux'):
@@ -128,7 +128,7 @@ def GypBuild():
     #     after the build proper that could be used for cumulative failures),
     #     use that instead of this. This isolates the final return value so
     #     that it isn't misattributed to the last stage.
-    print '@@@BUILD_STEP failures@@@'
+    print('@@@BUILD_STEP failures@@@')
     sys.exit(retcode)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/gyptest.py b/media/webrtc/trunk/tools/gyp/gyptest.py
index 8e4fc47d5c..b45c287717 100755
--- a/media/webrtc/trunk/tools/gyp/gyptest.py
+++ b/media/webrtc/trunk/tools/gyp/gyptest.py
@@ -13,7 +13,7 @@ import optparse
 import subprocess
 import sys
 
-class CommandRunner(object):
+class CommandRunner:
   """
   Executor class for commands, including "commands" implemented by
   Python functions.
@@ -51,7 +51,7 @@ class CommandRunner(object):
     if type(command) == type(()):
       func = command[0]
       args = command[1:]
-      s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
+      s = '{}({})'.format(func.__name__, ', '.join(map(repr, args)))
     if type(command) == type([]):
       # TODO:  quote arguments containing spaces
       # TODO:  handle meta characters?
@@ -69,7 +69,7 @@ class CommandRunner(object):
     """
     if not self.active:
       return 0
-    if type(command) == type(''):
+    if type(command) == str:
       command = self.subst(command)
       cmdargs = shlex.split(command)
       if cmdargs[0] == 'cd':
@@ -117,7 +117,7 @@ class CommandRunner(object):
     return self.execute(command, stdout, stderr)
 
 
-class Unbuffered(object):
+class Unbuffered:
   def __init__(self, fp):
     self.fp = fp
   def write(self, arg):
@@ -190,13 +190,13 @@ def main(argv=None):
       tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
     else:
       if not is_test_name(os.path.basename(arg)):
-        print >>sys.stderr, arg, 'is not a valid gyp test name.'
+        print(arg, 'is not a valid gyp test name.', file=sys.stderr)
         sys.exit(1)
       tests.append(arg)
 
   if opts.list:
     for test in tests:
-      print test
+      print(test)
     sys.exit(0)
 
   CommandRunner.verbose = not opts.quiet
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py
index 593f0e5b0b..71730e4ebb 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSNew.py
@@ -59,7 +59,7 @@ def MakeGuid(name, seed='msvs_new'):
 #------------------------------------------------------------------------------
 
 
-class MSVSSolutionEntry(object):
+class MSVSSolutionEntry:
   def __cmp__(self, other):
     # Sort by name then guid (so things are in order on vs2008).
     return cmp((self.name, self.get_guid()), (other.name, other.get_guid()))
@@ -172,7 +172,7 @@ class MSVSProject(MSVSSolutionEntry):
 #------------------------------------------------------------------------------
 
 
-class MSVSSolution(object):
+class MSVSSolution:
   """Visual Studio solution."""
 
   def __init__(self, path, version, entries=None, variants=None,
@@ -250,7 +250,7 @@ class MSVSSolution(object):
       # msbuild does not accept an empty folder_name.
       # use '.' in case relative_path is empty.
       folder_name = relative_path.replace('/', '\\') or '.'
-      f.write('Project("%s") = "%s", "%s", "%s"\r\n' % (
+      f.write('Project("{}") = "{}", "{}", "{}"\r\n'.format(
           e.entry_type_guid,          # Entry type GUID
           e.name,                     # Folder name
           folder_name,                # Folder name (again)
@@ -268,14 +268,14 @@ class MSVSSolution(object):
         if e.items:
           f.write('\tProjectSection(SolutionItems) = preProject\r\n')
           for i in e.items:
-            f.write('\t\t%s = %s\r\n' % (i, i))
+            f.write('\t\t{} = {}\r\n'.format(i, i))
           f.write('\tEndProjectSection\r\n')
 
       if isinstance(e, MSVSProject):
         if e.dependencies:
           f.write('\tProjectSection(ProjectDependencies) = postProject\r\n')
           for d in e.dependencies:
-            f.write('\t\t%s = %s\r\n' % (d.get_guid(), d.get_guid()))
+            f.write('\t\t{} = {}\r\n'.format(d.get_guid(), d.get_guid()))
           f.write('\tEndProjectSection\r\n')
 
       f.write('EndProject\r\n')
@@ -286,7 +286,7 @@ class MSVSSolution(object):
     # Configurations (variants)
     f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n')
     for v in self.variants:
-      f.write('\t\t%s = %s\r\n' % (v, v))
+      f.write('\t\t{} = {}\r\n'.format(v, v))
     f.write('\tEndGlobalSection\r\n')
 
     # Sort config guids for easier diffing of solution changes.
@@ -304,14 +304,14 @@ class MSVSSolution(object):
         nv = config_guids_overrides[g].get(v, v)
         # Pick which project configuration to build for this solution
         # configuration.
-        f.write('\t\t%s.%s.ActiveCfg = %s\r\n' % (
+        f.write('\t\t{}.{}.ActiveCfg = {}\r\n'.format(
             g,              # Project GUID
             v,              # Solution build configuration
             nv,             # Project build config for that solution config
         ))
 
         # Enable project in this solution configuration.
-        f.write('\t\t%s.%s.Build.0 = %s\r\n' % (
+        f.write('\t\t{}.{}.Build.0 = {}\r\n'.format(
             g,              # Project GUID
             v,              # Solution build configuration
             nv,             # Project build config for that solution config
@@ -332,7 +332,7 @@ class MSVSSolution(object):
         if not isinstance(e, MSVSFolder):
           continue        # Does not apply to projects, only folders
         for subentry in e.entries:
-          f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
+          f.write('\t\t{} = {}\r\n'.format(subentry.get_guid(), e.get_guid()))
       f.write('\tEndGlobalSection\r\n')
 
     f.write('EndGlobal\r\n')
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSProject.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSProject.py
index db1ceede34..0b74fb8996 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSProject.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSProject.py
@@ -10,7 +10,7 @@ import gyp.easy_xml as easy_xml
 #------------------------------------------------------------------------------
 
 
-class Tool(object):
+class Tool:
   """Visual Studio tool."""
 
   def __init__(self, name, attrs=None):
@@ -31,7 +31,7 @@ class Tool(object):
     """
     return ['Tool', self._attrs]
 
-class Filter(object):
+class Filter:
   """Visual Studio filter - that is, a virtual folder."""
 
   def __init__(self, name, contents=None):
@@ -48,7 +48,7 @@ class Filter(object):
 #------------------------------------------------------------------------------
 
 
-class Writer(object):
+class Writer:
   """Visual Studio XML project writer."""
 
   def __init__(self, project_path, version, name, guid=None, platforms=None):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py
index 8ae19180ea..993c2f0115 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSSettings.py
@@ -32,7 +32,7 @@ _msvs_to_msbuild_converters = {}
 _msbuild_name_of_tool = {}
 
 
-class _Tool(object):
+class _Tool:
   """Represents a tool used by MSVS or MSBuild.
 
   Attributes:
@@ -64,7 +64,7 @@ def _GetMSBuildToolSettings(msbuild_settings, tool):
   return msbuild_settings.setdefault(tool.msbuild_name, {})
 
 
-class _Type(object):
+class _Type:
   """Type of settings (Base class)."""
 
   def ValidateMSVS(self, value):
@@ -106,11 +106,11 @@ class _String(_Type):
   """A setting that's just a string."""
 
   def ValidateMSVS(self, value):
-    if not isinstance(value, basestring):
+    if not isinstance(value, str):
       raise ValueError('expected string; got %r' % value)
 
   def ValidateMSBuild(self, value):
-    if not isinstance(value, basestring):
+    if not isinstance(value, str):
       raise ValueError('expected string; got %r' % value)
 
   def ConvertToMSBuild(self, value):
@@ -122,11 +122,11 @@ class _StringList(_Type):
   """A settings that's a list of strings."""
 
   def ValidateMSVS(self, value):
-    if not isinstance(value, basestring) and not isinstance(value, list):
+    if not isinstance(value, str) and not isinstance(value, list):
       raise ValueError('expected string list; got %r' % value)
 
   def ValidateMSBuild(self, value):
-    if not isinstance(value, basestring) and not isinstance(value, list):
+    if not isinstance(value, str) and not isinstance(value, list):
       raise ValueError('expected string list; got %r' % value)
 
   def ConvertToMSBuild(self, value):
@@ -191,8 +191,8 @@ class _Enumeration(_Type):
   def __init__(self, label_list, new=None):
     _Type.__init__(self)
     self._label_list = label_list
-    self._msbuild_values = set(value for value in label_list
-                               if value is not None)
+    self._msbuild_values = {value for value in label_list
+                               if value is not None}
     if new is not None:
       self._msbuild_values.update(new)
 
@@ -337,7 +337,7 @@ def _ConvertedToAdditionalOption(tool, msvs_name, flag):
     if value == 'true':
       tool_settings = _GetMSBuildToolSettings(msbuild_settings, tool)
       if 'AdditionalOptions' in tool_settings:
-        new_flags = '%s %s' % (tool_settings['AdditionalOptions'], flag)
+        new_flags = '{} {}'.format(tool_settings['AdditionalOptions'], flag)
       else:
         new_flags = flag
       tool_settings['AdditionalOptions'] = new_flags
@@ -400,7 +400,7 @@ def _ValidateExclusionSetting(setting, settings, error_msg, stderr=sys.stderr):
 
   if unrecognized:
     # We don't know this setting. Give a warning.
-    print >> stderr, error_msg
+    print(error_msg, file=stderr)
 
 
 def FixVCMacroSlashes(s):
@@ -433,7 +433,7 @@ def ConvertVCMacrosToMSBuild(s):
         '$(PlatformName)': '$(Platform)',
         '$(SafeInputName)': '%(Filename)',
     }
-    for old, new in replace_map.iteritems():
+    for old, new in replace_map.items():
       s = s.replace(old, new)
     s = FixVCMacroSlashes(s)
   return s
@@ -453,17 +453,17 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
       dictionaries of settings and their values.
   """
   msbuild_settings = {}
-  for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems():
+  for msvs_tool_name, msvs_tool_settings in msvs_settings.items():
     if msvs_tool_name in _msvs_to_msbuild_converters:
       msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name]
-      for msvs_setting, msvs_value in msvs_tool_settings.iteritems():
+      for msvs_setting, msvs_value in msvs_tool_settings.items():
         if msvs_setting in msvs_tool:
           # Invoke the translation function.
           try:
             msvs_tool[msvs_setting](msvs_value, msbuild_settings)
-          except ValueError, e:
-            print >> stderr, ('Warning: while converting %s/%s to MSBuild, '
-                              '%s' % (msvs_tool_name, msvs_setting, e))
+          except ValueError as e:
+            print(('Warning: while converting %s/%s to MSBuild, '
+                              '%s' % (msvs_tool_name, msvs_setting, e)), file=stderr)
         else:
           _ValidateExclusionSetting(msvs_setting,
                                     msvs_tool,
@@ -472,8 +472,8 @@ def ConvertToMSBuildSettings(msvs_settings, stderr=sys.stderr):
                                      (msvs_tool_name, msvs_setting)),
                                     stderr)
     else:
-      print >> stderr, ('Warning: unrecognized tool %s while converting to '
-                        'MSBuild.' % msvs_tool_name)
+      print(('Warning: unrecognized tool %s while converting to '
+                        'MSBuild.' % msvs_tool_name), file=stderr)
   return msbuild_settings
 
 
@@ -513,13 +513,13 @@ def _ValidateSettings(validators, settings, stderr):
   for tool_name in settings:
     if tool_name in validators:
       tool_validators = validators[tool_name]
-      for setting, value in settings[tool_name].iteritems():
+      for setting, value in settings[tool_name].items():
         if setting in tool_validators:
           try:
             tool_validators[setting](value)
-          except ValueError, e:
-            print >> stderr, ('Warning: for %s/%s, %s' %
-                              (tool_name, setting, e))
+          except ValueError as e:
+            print(('Warning: for %s/%s, %s' %
+                              (tool_name, setting, e)), file=stderr)
         else:
           _ValidateExclusionSetting(setting,
                                     tool_validators,
@@ -528,7 +528,7 @@ def _ValidateSettings(validators, settings, stderr):
                                     stderr)
 
     else:
-      print >> stderr, ('Warning: unrecognized tool %s' % tool_name)
+      print(('Warning: unrecognized tool %s' % tool_name), file=stderr)
 
 
 # MSVS and MBuild names of the tools.
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSToolFile.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSToolFile.py
index 74e529a17f..ef5b12231f 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSToolFile.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSToolFile.py
@@ -8,7 +8,7 @@ import gyp.common
 import gyp.easy_xml as easy_xml
 
 
-class Writer(object):
+class Writer:
   """Visual Studio XML tool file writer."""
 
   def __init__(self, tool_file_path, name):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUserFile.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUserFile.py
index 6c07e9a893..6dda1e1b03 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUserFile.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUserFile.py
@@ -51,7 +51,7 @@ def _QuoteWin32CommandLineArgs(args):
     new_args.append(arg)
   return new_args
 
-class Writer(object):
+class Writer:
   """Visual Studio XML user user file writer."""
 
   def __init__(self, user_file_path, version, name):
@@ -90,8 +90,8 @@ class Writer(object):
     abs_command = _FindCommandInPath(command[0])
 
     if environment and isinstance(environment, dict):
-      env_list = ['%s="%s"' % (key, val)
-                  for (key,val) in environment.iteritems()]
+      env_list = ['{}="{}"'.format(key, val)
+                  for (key,val) in environment.items()]
       environment = ' '.join(env_list)
     else:
       environment = ''
@@ -135,7 +135,7 @@ class Writer(object):
   def WriteIfChanged(self):
     """Writes the user file."""
     configs = ['Configurations']
-    for config, spec in sorted(self.configurations.iteritems()):
+    for config, spec in sorted(self.configurations.items()):
       configs.append(spec)
 
     content = ['VisualStudioUserFile',
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUtil.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUtil.py
index 96dea6c2c9..28b725d00c 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUtil.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSUtil.py
@@ -55,7 +55,7 @@ def _SuffixName(name, suffix):
     Target name with suffix added (foo_suffix#target)
   """
   parts = name.rsplit('#', 1)
-  parts[0] = '%s_%s' % (parts[0], suffix)
+  parts[0] = '{}_{}'.format(parts[0], suffix)
   return '#'.join(parts)
 
 
@@ -160,7 +160,7 @@ def _GetPdbPath(target_dict, config_name, vars):
 
 
   pdb_base = target_dict.get('product_name', target_dict['target_name'])
-  pdb_base = '%s.%s.pdb' % (pdb_base, TARGET_TYPE_EXT[target_dict['type']])
+  pdb_base = '{}.{}.pdb'.format(pdb_base, TARGET_TYPE_EXT[target_dict['type']])
   pdb_path = vars['PRODUCT_DIR'] + '/' + pdb_base
 
   return pdb_path
@@ -236,7 +236,7 @@ def InsertLargePdbShims(target_list, target_dicts, vars):
 
     # Set up the shim to output its PDB to the same location as the final linker
     # target.
-    for config_name, config in shim_dict.get('configurations').iteritems():
+    for config_name, config in shim_dict.get('configurations').items():
       pdb_path = _GetPdbPath(target_dict, config_name, vars)
 
       # A few keys that we don't want to propagate.
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py
index edaf6eed00..6ff461102f 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/MSVSVersion.py
@@ -13,7 +13,7 @@ import gyp
 import glob
 
 
-class VisualStudioVersion(object):
+class VisualStudioVersion:
   """Information regarding a version of Visual Studio."""
 
   def __init__(self, short_name, description,
@@ -168,7 +168,7 @@ def _RegistryQuery(key, value=None):
   text = None
   try:
     text = _RegistryQueryBase('Sysnative', key, value)
-  except OSError, e:
+  except OSError as e:
     if e.errno == errno.ENOENT:
       text = _RegistryQueryBase('System32', key, value)
     else:
@@ -186,13 +186,13 @@ def _RegistryGetValueUsingWinReg(key, value):
     contents of the registry key's value, or None on failure.  Throws
     ImportError if _winreg is unavailable.
   """
-  import _winreg
+  import six.moves.winreg
   try:
     root, subkey = key.split('\\', 1)
     assert root == 'HKLM'  # Only need HKLM for now.
-    with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
-      return _winreg.QueryValueEx(hkey, value)[0]
-  except WindowsError:
+    with six.moves.winreg.OpenKey(six.moves.winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
+      return six.moves.winreg.QueryValueEx(hkey, value)[0]
+  except OSError:
     return None
 
 
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py
index b26977592b..6871786a60 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/__init__.py
@@ -34,8 +34,8 @@ def DebugOutput(mode, message, *args):
       pass
     if args:
       message %= args
-    print '%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
-                              ctx[1], ctx[2], message)
+    print('%s:%s:%d:%s %s' % (mode.upper(), os.path.basename(ctx[0]),
+                              ctx[1], ctx[2], message))
 
 def FindBuildFiles():
   extension = '.gyp'
@@ -163,7 +163,7 @@ def ShlexEnv(env_name):
 
 def FormatOpt(opt, value):
   if opt.startswith('--'):
-    return '%s=%s' % (opt, value)
+    return '{}={}'.format(opt, value)
   return opt + value
 
 def RegenerateAppendFlag(flag, values, predicate, env_name, options):
@@ -210,7 +210,7 @@ def RegenerateFlags(options):
   # We always want to ignore the environment when regenerating, to avoid
   # duplicate or changed flags in the environment at the time of regeneration.
   flags = ['--ignore-environment']
-  for name, metadata in options._regeneration_metadata.iteritems():
+  for name, metadata in options._regeneration_metadata.items():
     opt = metadata['opt']
     value = getattr(options, name)
     value_predicate = metadata['type'] == 'path' and FixPath or Noop
@@ -229,12 +229,12 @@ def RegenerateFlags(options):
           (action == 'store_false' and not value)):
         flags.append(opt)
       elif options.use_environment and env_name:
-        print >>sys.stderr, ('Warning: environment regeneration unimplemented '
+        print(('Warning: environment regeneration unimplemented '
                              'for %s flag %r env_name %r' % (action, opt,
-                                                             env_name))
+                                                             env_name)), file=sys.stderr)
     else:
-      print >>sys.stderr, ('Warning: regeneration unimplemented for action %r '
-                           'flag %r' % (action, opt))
+      print(('Warning: regeneration unimplemented for action %r '
+                           'flag %r' % (action, opt)), file=sys.stderr)
 
   return flags
 
@@ -413,7 +413,7 @@ def gyp_main(args):
     for option, value in sorted(options.__dict__.items()):
       if option[0] == '_':
         continue
-      if isinstance(value, basestring):
+      if isinstance(value, str):
         DebugOutput(DEBUG_GENERAL, "  %s: '%s'", option, value)
       else:
         DebugOutput(DEBUG_GENERAL, "  %s: %s", option, value)
@@ -435,7 +435,7 @@ def gyp_main(args):
       build_file_dir = os.path.abspath(os.path.dirname(build_file))
       build_file_dir_components = build_file_dir.split(os.path.sep)
       components_len = len(build_file_dir_components)
-      for index in xrange(components_len - 1, -1, -1):
+      for index in range(components_len - 1, -1, -1):
         if build_file_dir_components[index] == 'src':
           options.depth = os.path.sep.join(build_file_dir_components)
           break
@@ -478,7 +478,7 @@ def gyp_main(args):
   if home_dot_gyp != None:
     default_include = os.path.join(home_dot_gyp, 'include.gypi')
     if os.path.exists(default_include):
-      print 'Using overrides found in ' + default_include
+      print('Using overrides found in ' + default_include)
       includes.append(default_include)
 
   # Command-line --include files come after the default include.
@@ -493,7 +493,7 @@ def gyp_main(args):
   if options.generator_flags:
     gen_flags += options.generator_flags
   generator_flags = NameValueListToDict(gen_flags)
-  if DEBUG_GENERAL in gyp.debug.keys():
+  if DEBUG_GENERAL in list(gyp.debug.keys()):
     DebugOutput(DEBUG_GENERAL, "generator_flags: %s", generator_flags)
 
   # Generate all requested formats (use a set in case we got one format request
@@ -526,7 +526,7 @@ def gyp_main(args):
     generator.GenerateOutput(flat_list, targets, data, params)
 
     if options.configs:
-      valid_configs = targets[flat_list[0]]['configurations'].keys()
+      valid_configs = list(targets[flat_list[0]]['configurations'].keys())
       for conf in options.configs:
         if conf not in valid_configs:
           raise GypError('Invalid config specified via --build: %s' % conf)
@@ -539,7 +539,7 @@ def gyp_main(args):
 def main(args):
   try:
     return gyp_main(args)
-  except GypError, e:
+  except GypError as e:
     sys.stderr.write("gyp: %s\n" % e)
     return 1
 
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py
index a1e1db5f12..63effe882e 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/common.py
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from __future__ import with_statement
 
 import collections
 import errno
@@ -15,7 +14,7 @@ import sys
 
 # A minimal memoizing decorator. It'll blow up if the args aren't immutable,
 # among other "problems".
-class memoize(object):
+class memoize:
   def __init__(self, func):
     self.func = func
     self.cache = {}
@@ -336,7 +335,7 @@ def WriteOnDiff(filename):
     the target if it differs (on close).
   """
 
-  class Writer(object):
+  class Writer:
     """Wrapper around file which only covers the target if it differs."""
     def __init__(self):
       # Pick temporary file.
@@ -363,7 +362,7 @@ def WriteOnDiff(filename):
         same = False
         try:
           same = filecmp.cmp(self.tmp_path, filename, False)
-        except OSError, e:
+        except OSError as e:
           if e.errno != errno.ENOENT:
             raise
 
@@ -382,9 +381,9 @@ def WriteOnDiff(filename):
           #
           # No way to get the umask without setting a new one?  Set a safe one
           # and then set it back to the old value.
-          umask = os.umask(077)
+          umask = os.umask(0o77)
           os.umask(umask)
-          os.chmod(self.tmp_path, 0666 & ~umask)
+          os.chmod(self.tmp_path, 0o666 & ~umask)
           if sys.platform == 'win32' and os.path.exists(filename):
             # NOTE: on windows (but not cygwin) rename will not replace an
             # existing file, so it must be preceded with a remove. Sadly there
@@ -467,7 +466,7 @@ def CopyTool(flavor, out_path, generator_flags={}):
         ''.join([source[0], header] + source[1:]))
 
   # Make file executable.
-  os.chmod(tool_path, 0755)
+  os.chmod(tool_path, 0o755)
 
 
 # From Alex Martelli,
@@ -490,7 +489,7 @@ def uniquer(seq, idfun=None):
 
 
 # Based on http://code.activestate.com/recipes/576694/.
-class OrderedSet(collections.MutableSet):
+class OrderedSet(collections.abc.MutableSet):
   def __init__(self, iterable=None):
     self.end = end = []
     end += [None, end, end]         # sentinel node for doubly linked list
@@ -540,8 +539,8 @@ class OrderedSet(collections.MutableSet):
 
   def __repr__(self):
     if not self:
-      return '%s()' % (self.__class__.__name__,)
-    return '%s(%r)' % (self.__class__.__name__, list(self))
+      return '{}()'.format(self.__class__.__name__)
+    return '{}({!r})'.format(self.__class__.__name__, list(self))
 
   def __eq__(self, other):
     if isinstance(other, OrderedSet):
@@ -580,7 +579,7 @@ def TopologicallySorted(graph, get_edges):
     graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'}
     def GetEdges(node):
       return re.findall(r'\$\(([^))]\)', graph[node])
-    print TopologicallySorted(graph.keys(), GetEdges)
+    print(TopologicallySorted(graph.keys(), GetEdges))
     ==>
     ['a', 'c', b']
   """
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py
index ad6f9a1438..a009f32389 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/common_test.py
@@ -23,7 +23,7 @@ class TestTopologicallySorted(unittest.TestCase):
     def GetEdge(node):
       return tuple(graph[node])
     self.assertEqual(
-      gyp.common.TopologicallySorted(graph.keys(), GetEdge),
+      gyp.common.TopologicallySorted(list(graph.keys()), GetEdge),
       ['a', 'c', 'd', 'b'])
 
   def test_Cycle(self):
@@ -38,7 +38,7 @@ class TestTopologicallySorted(unittest.TestCase):
       return tuple(graph[node])
     self.assertRaises(
       gyp.common.CycleError, gyp.common.TopologicallySorted,
-      graph.keys(), GetEdge)
+      list(graph.keys()), GetEdge)
 
 
 class TestGetFlavor(unittest.TestCase):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/easy_xml.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/easy_xml.py
index bf949b6ac9..6f396f6b9f 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/easy_xml.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/easy_xml.py
@@ -4,6 +4,7 @@
 
 import re
 import os
+from functools import reduce
 
 
 def XmlToString(content, encoding='utf-8', pretty=False):
@@ -79,8 +80,8 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
   # Optionally in second position is a dictionary of the attributes.
   rest = specification[1:]
   if rest and isinstance(rest[0], dict):
-    for at, val in sorted(rest[0].iteritems()):
-      xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
+    for at, val in sorted(rest[0].items()):
+      xml_parts.append(' {}="{}"'.format(at, _XmlEscape(val, attr=True)))
     rest = rest[1:]
   if rest:
     xml_parts.append('>')
@@ -97,7 +98,7 @@ def _ConstructContentList(xml_parts, specification, pretty, level=0):
         _ConstructContentList(xml_parts, child_spec, pretty, level + 1)
     if multi_line and indentation:
       xml_parts.append(indentation)
-    xml_parts.append('</%s>%s' % (name, new_line))
+    xml_parts.append('</{}>{}'.format(name, new_line))
   else:
     xml_parts.append('/>%s' % new_line)
 
@@ -118,7 +119,7 @@ def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
 
   # Get the old content
   try:
-    f = open(path, 'r')
+    f = open(path)
     existing = f.read()
     f.close()
   except:
@@ -143,7 +144,7 @@ _xml_escape_map = {
 
 
 _xml_escape_re = re.compile(
-    "(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
+    "(%s)" % "|".join(map(re.escape, list(_xml_escape_map.keys()))))
 
 
 def _XmlEscape(value, attr=False):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/flock_tool.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/flock_tool.py
index b38d8660f7..0cccb49c69 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/flock_tool.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/flock_tool.py
@@ -18,7 +18,7 @@ def main(args):
   executor.Dispatch(args)
 
 
-class FlockTool(object):
+class FlockTool:
   """This class emulates the 'flock' command."""
   def Dispatch(self, args):
     """Dispatches a string command to a method."""
@@ -39,7 +39,7 @@ class FlockTool(object):
     # where fcntl.flock(fd, LOCK_EX) always fails
     # with EBADF, that's why we use this F_SETLK
     # hack instead.
-    fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0666)
+    fd = os.open(lockfile, os.O_WRONLY|os.O_NOCTTY|os.O_CREAT, 0o666)
     if sys.platform.startswith('aix'):
       # Python on AIX is compiled with LARGEFILE support, which changes the
       # struct size.
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/analyzer.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/analyzer.py
index 921c1a6b71..5922b9a834 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/analyzer.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/analyzer.py
@@ -68,6 +68,7 @@ import json
 import os
 import posixpath
 import sys
+import six
 
 debug = False
 
@@ -155,7 +156,7 @@ def _AddSources(sources, base_path, base_path_components, result):
       continue
     result.append(base_path + source)
     if debug:
-      print 'AddSource', org_source, result[len(result) - 1]
+      print('AddSource', org_source, result[len(result) - 1])
 
 
 def _ExtractSourcesFromAction(action, base_path, base_path_components,
@@ -185,7 +186,7 @@ def _ExtractSources(target, target_dict, toplevel_dir):
     base_path += '/'
 
   if debug:
-    print 'ExtractSources', target, base_path
+    print('ExtractSources', target, base_path)
 
   results = []
   if 'sources' in target_dict:
@@ -204,7 +205,7 @@ def _ExtractSources(target, target_dict, toplevel_dir):
   return results
 
 
-class Target(object):
+class Target:
   """Holds information about a particular target:
   deps: set of Targets this Target depends upon. This is not recursive, only the
     direct dependent Targets.
@@ -239,7 +240,7 @@ class Target(object):
     self.is_or_has_linked_ancestor = False
 
 
-class Config(object):
+class Config:
   """Details what we're looking for
   files: set of files to search for
   targets: see file description for details."""
@@ -257,10 +258,10 @@ class Config(object):
     if not config_path:
       return
     try:
-      f = open(config_path, 'r')
+      f = open(config_path)
       config = json.load(f)
       f.close()
-    except IOError:
+    except OSError:
       raise Exception('Unable to open file ' + config_path)
     except ValueError as e:
       raise Exception('Unable to parse config file ' + config_path + str(e))
@@ -278,7 +279,7 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir):
   the root of the source tree."""
   if _ToLocalPath(toplevel_dir, _ToGypPath(build_file)) in files:
     if debug:
-      print 'gyp file modified', build_file
+      print('gyp file modified', build_file)
     return True
 
   # First element of included_files is the file itself.
@@ -291,8 +292,8 @@ def _WasBuildFileModified(build_file, data, files, toplevel_dir):
         _ToGypPath(gyp.common.UnrelativePath(include_file, build_file))
     if _ToLocalPath(toplevel_dir, rel_include_file) in files:
       if debug:
-        print 'included gyp file modified, gyp_file=', build_file, \
-            'included file=', rel_include_file
+        print('included gyp file modified, gyp_file=', build_file, \
+            'included file=', rel_include_file)
       return True
   return False
 
@@ -373,7 +374,7 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
     # If a build file (or any of its included files) is modified we assume all
     # targets in the file are modified.
     if build_file_in_files[build_file]:
-      print 'matching target from modified build file', target_name
+      print('matching target from modified build file', target_name)
       target.match_status = MATCH_STATUS_MATCHES
       matching_targets.append(target)
     else:
@@ -381,7 +382,7 @@ def _GenerateTargets(data, target_list, target_dicts, toplevel_dir, files,
                                 toplevel_dir)
       for source in sources:
         if _ToGypPath(os.path.normpath(source)) in files:
-          print 'target', target_name, 'matches', source
+          print('target', target_name, 'matches', source)
           target.match_status = MATCH_STATUS_MATCHES
           matching_targets.append(target)
           break
@@ -433,7 +434,7 @@ def _DoesTargetDependOnMatchingTargets(target):
   for dep in target.deps:
     if _DoesTargetDependOnMatchingTargets(dep):
       target.match_status = MATCH_STATUS_MATCHES_BY_DEPENDENCY
-      print '\t', target.name, 'matches by dep', dep.name
+      print('\t', target.name, 'matches by dep', dep.name)
       return True
   target.match_status = MATCH_STATUS_DOESNT_MATCH
   return False
@@ -445,7 +446,7 @@ def _GetTargetsDependingOnMatchingTargets(possible_targets):
   supplied as input to analyzer.
   possible_targets: targets to search from."""
   found = []
-  print 'Targets that matched by dependency:'
+  print('Targets that matched by dependency:')
   for target in possible_targets:
     if _DoesTargetDependOnMatchingTargets(target):
       found.append(target)
@@ -484,12 +485,12 @@ def _AddCompileTargets(target, roots, add_if_no_ancestor, result):
           (add_if_no_ancestor or target.requires_build)) or
          (target.is_static_library and add_if_no_ancestor and
           not target.is_or_has_linked_ancestor)):
-    print '\t\tadding to compile targets', target.name, 'executable', \
+    print('\t\tadding to compile targets', target.name, 'executable', \
            target.is_executable, 'added_to_compile_targets', \
            target.added_to_compile_targets, 'add_if_no_ancestor', \
            add_if_no_ancestor, 'requires_build', target.requires_build, \
            'is_static_library', target.is_static_library, \
-           'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor
+           'is_or_has_linked_ancestor', target.is_or_has_linked_ancestor)
     result.add(target)
     target.added_to_compile_targets = True
 
@@ -500,7 +501,7 @@ def _GetCompileTargets(matching_targets, supplied_targets):
   supplied_targets: set of targets supplied to analyzer to search from."""
   result = set()
   for target in matching_targets:
-    print 'finding compile targets for match', target.name
+    print('finding compile targets for match', target.name)
     _AddCompileTargets(target, supplied_targets, True, result)
   return result
 
@@ -508,46 +509,46 @@ def _GetCompileTargets(matching_targets, supplied_targets):
 def _WriteOutput(params, **values):
   """Writes the output, either to stdout or a file is specified."""
   if 'error' in values:
-    print 'Error:', values['error']
+    print('Error:', values['error'])
   if 'status' in values:
-    print values['status']
+    print(values['status'])
   if 'targets' in values:
     values['targets'].sort()
-    print 'Supplied targets that depend on changed files:'
+    print('Supplied targets that depend on changed files:')
     for target in values['targets']:
-      print '\t', target
+      print('\t', target)
   if 'invalid_targets' in values:
     values['invalid_targets'].sort()
-    print 'The following targets were not found:'
+    print('The following targets were not found:')
     for target in values['invalid_targets']:
-      print '\t', target
+      print('\t', target)
   if 'build_targets' in values:
     values['build_targets'].sort()
-    print 'Targets that require a build:'
+    print('Targets that require a build:')
     for target in values['build_targets']:
-      print '\t', target
+      print('\t', target)
   if 'compile_targets' in values:
     values['compile_targets'].sort()
-    print 'Targets that need to be built:'
+    print('Targets that need to be built:')
     for target in values['compile_targets']:
-      print '\t', target
+      print('\t', target)
   if 'test_targets' in values:
     values['test_targets'].sort()
-    print 'Test targets:'
+    print('Test targets:')
     for target in values['test_targets']:
-      print '\t', target
+      print('\t', target)
 
   output_path = params.get('generator_flags', {}).get(
       'analyzer_output_path', None)
   if not output_path:
-    print json.dumps(values)
+    print(json.dumps(values))
     return
   try:
     f = open(output_path, 'w')
     f.write(json.dumps(values) + '\n')
     f.close()
-  except IOError as e:
-    print 'Error writing to output file', output_path, str(e)
+  except OSError as e:
+    print('Error writing to output file', output_path, str(e))
 
 
 def _WasGypIncludeFileModified(params, files):
@@ -556,7 +557,7 @@ def _WasGypIncludeFileModified(params, files):
   if params['options'].includes:
     for include in params['options'].includes:
       if _ToGypPath(os.path.normpath(include)) in files:
-        print 'Include file modified, assuming all changed', include
+        print('Include file modified, assuming all changed', include)
         return True
   return False
 
@@ -595,7 +596,7 @@ def CalculateVariables(default_variables, params):
     default_variables.setdefault('OS', operating_system)
 
 
-class TargetCalculator(object):
+class TargetCalculator:
   """Calculates the matching test_targets and matching compile_targets."""
   def __init__(self, files, additional_compile_target_names, test_target_names,
                data, target_list, target_dicts, toplevel_dir, build_files):
@@ -638,13 +639,13 @@ class TargetCalculator(object):
                                   set(self._root_targets))]
     else:
       test_targets = [x for x in test_targets_no_all]
-    print 'supplied test_targets'
+    print('supplied test_targets')
     for target_name in self._test_target_names:
-      print '\t', target_name
-    print 'found test_targets'
+      print('\t', target_name)
+    print('found test_targets')
     for target in test_targets:
-      print '\t', target.name
-    print 'searching for matching test targets'
+      print('\t', target.name)
+    print('searching for matching test targets')
     matching_test_targets = _GetTargetsDependingOnMatchingTargets(test_targets)
     matching_test_targets_contains_all = (test_target_names_contains_all and
                                           set(matching_test_targets) &
@@ -654,14 +655,14 @@ class TargetCalculator(object):
       # 'all' is subsequentely added to the matching names below.
       matching_test_targets = [x for x in (set(matching_test_targets) &
                                            set(test_targets_no_all))]
-    print 'matched test_targets'
+    print('matched test_targets')
     for target in matching_test_targets:
-      print '\t', target.name
+      print('\t', target.name)
     matching_target_names = [gyp.common.ParseQualifiedTarget(target.name)[1]
                              for target in matching_test_targets]
     if matching_test_targets_contains_all:
       matching_target_names.append('all')
-      print '\tall'
+      print('\tall')
     return matching_target_names
 
   def find_matching_compile_target_names(self):
@@ -669,7 +670,7 @@ class TargetCalculator(object):
     assert self.is_build_impacted();
     # Compile targets are found by searching up from changed targets.
     # Reset the visited status for _GetBuildTargets.
-    for target in self._name_to_target.itervalues():
+    for target in self._name_to_target.values():
       target.visited = False
 
     supplied_targets = _LookupTargets(self._supplied_target_names_no_all(),
@@ -677,10 +678,10 @@ class TargetCalculator(object):
     if 'all' in self._supplied_target_names():
       supplied_targets = [x for x in (set(supplied_targets) |
                                       set(self._root_targets))]
-    print 'Supplied test_targets & compile_targets'
+    print('Supplied test_targets & compile_targets')
     for target in supplied_targets:
-      print '\t', target.name
-    print 'Finding compile targets'
+      print('\t', target.name)
+    print('Finding compile targets')
     compile_targets = _GetCompileTargets(self._changed_targets,
                                          supplied_targets)
     return [gyp.common.ParseQualifiedTarget(target.name)[1]
@@ -699,7 +700,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
 
     toplevel_dir = _ToGypPath(os.path.abspath(params['options'].toplevel_dir))
     if debug:
-      print 'toplevel_dir', toplevel_dir
+      print('toplevel_dir', toplevel_dir)
 
     if _WasGypIncludeFileModified(params, config.files):
       result_dict = { 'status': all_changed_string,
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/cmake.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/cmake.py
index a2b96291aa..351a30da70 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/cmake.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/cmake.py
@@ -214,7 +214,7 @@ def WriteVariable(output, variable_name, prepend=None):
   output.write('}')
 
 
-class CMakeTargetType(object):
+class CMakeTargetType:
   def __init__(self, command, modifier, property_modifier):
     self.command = command
     self.modifier = modifier
@@ -255,7 +255,7 @@ def WriteActions(target_name, actions, extra_sources, extra_deps,
   """
   for action in actions:
     action_name = StringToCMakeTargetName(action['action_name'])
-    action_target_name = '%s__%s' % (target_name, action_name)
+    action_target_name = '{}__{}'.format(target_name, action_name)
 
     inputs = action['inputs']
     inputs_name = action_target_name + '__input'
@@ -270,10 +270,10 @@ def WriteActions(target_name, actions, extra_sources, extra_deps,
 
     # Build up a list of outputs.
     # Collect the output dirs we'll need.
-    dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+    dirs = {dir for dir in (os.path.dirname(o) for o in outputs) if dir}
 
     if int(action.get('process_outputs_as_sources', False)):
-      extra_sources.extend(zip(cmake_outputs, outputs))
+      extra_sources.extend(list(zip(cmake_outputs, outputs)))
 
     # add_custom_command
     output.write('add_custom_command(OUTPUT ')
@@ -363,7 +363,7 @@ def WriteRules(target_name, rules, extra_sources, extra_deps,
 
       # Build up a list of outputs.
       # Collect the output dirs we'll need.
-      dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
+      dirs = {dir for dir in (os.path.dirname(o) for o in outputs) if dir}
 
       # Create variables for the output, as 'local' variable will be unset.
       these_outputs = []
@@ -462,7 +462,7 @@ def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
     extra_deps.append(copy_name)
     return
 
-  class Copy(object):
+  class Copy:
     def __init__(self, ext, command):
       self.cmake_inputs = []
       self.cmake_outputs = []
@@ -569,7 +569,7 @@ def CreateCMakeTargetFullName(qualified_target):
   return StringToCMakeTargetName(cmake_target_full_name)
 
 
-class CMakeNamer(object):
+class CMakeNamer:
   """Converts Gyp target names into CMake target names.
 
   CMake requires that target names be globally unique. One way to ensure
@@ -644,7 +644,7 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
 
   cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
   if cmake_target_type is None:
-    print ('Target %s has unknown target type %s, skipping.' %
+    print('Target %s has unknown target type %s, skipping.' %
           (        target_name,               target_type  ) )
     return
 
@@ -868,8 +868,8 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
       default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
 
     elif target_type != 'executable':
-      print ('ERROR: What output file should be generated?',
-              'type', target_type, 'target', target_name)
+      print(('ERROR: What output file should be generated?',
+              'type', target_type, 'target', target_name))
 
     product_prefix = spec.get('product_prefix', default_product_prefix)
     product_name = spec.get('product_name', default_product_name)
@@ -979,7 +979,7 @@ def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
 
     # XCode settings
     xcode_settings = config.get('xcode_settings', {})
-    for xcode_setting, xcode_value in xcode_settings.viewitems():
+    for xcode_setting, xcode_value in xcode_settings.items():
       SetTargetProperty(output, cmake_target_name,
                         "XCODE_ATTRIBUTE_%s" % xcode_setting, xcode_value,
                         '' if isinstance(xcode_value, str) else ' ')
@@ -1207,11 +1207,11 @@ def PerformBuild(data, configurations, params):
                                               output_dir,
                                               config_name))
     arguments = ['cmake', '-G', 'Ninja']
-    print 'Generating [%s]: %s' % (config_name, arguments)
+    print('Generating [{}]: {}'.format(config_name, arguments))
     subprocess.check_call(arguments, cwd=build_dir)
 
     arguments = ['ninja', '-C', build_dir]
-    print 'Building [%s]: %s' % (config_name, arguments)
+    print('Building [{}]: {}'.format(config_name, arguments))
     subprocess.check_call(arguments)
 
 
@@ -1230,7 +1230,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     GenerateOutputForConfig(target_list, target_dicts, data,
                             params, user_config)
   else:
-    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    config_names = list(target_dicts[target_list[0]]['configurations'].keys())
     if params['parallel']:
       try:
         pool = multiprocessing.Pool(len(config_names))
@@ -1239,7 +1239,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           arglists.append((target_list, target_dicts, data,
                            params, config_name))
           pool.map(CallGenerateOutputForConfig, arglists)
-      except KeyboardInterrupt, e:
+      except KeyboardInterrupt as e:
         pool.terminate()
         raise e
     else:
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py
index 160eafe2ef..719b6c1e54 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/dump_dependency_json.py
@@ -96,4 +96,4 @@ def GenerateOutput(target_list, target_dicts, data, params):
   f = open(filename, 'w')
   json.dump(edges, f)
   f.close()
-  print 'Wrote json to %s.' % filename
+  print('Wrote json to %s.' % filename)
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py
index 3544347b3b..a226c19fc5 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/eclipse.py
@@ -24,7 +24,7 @@ import gyp
 import gyp.common
 import gyp.msvs_emulation
 import shlex
-import xml.etree.cElementTree as ET
+import xml.etree.ElementTree as ET
 
 generator_wants_static_library_dependencies_adjusted = False
 
@@ -141,7 +141,7 @@ def GetAllIncludeDirectories(target_list, target_dicts,
             compiler_includes_list.append(include_dir)
 
       # Find standard gyp include dirs.
-      if config.has_key('include_dirs'):
+      if 'include_dirs' in config:
         include_dirs = config['include_dirs']
         for shared_intermediate_dir in shared_intermediate_dirs:
           for include_dir in include_dirs:
@@ -272,7 +272,7 @@ def WriteMacros(out, eclipse_langs, defines):
   out.write('    <language name="holder for library settings"></language>\n')
   for lang in eclipse_langs:
     out.write('    <language name="%s">\n' % lang)
-    for key in sorted(defines.iterkeys()):
+    for key in sorted(defines.keys()):
       out.write('      <macro><name>%s</name><value>%s</value></macro>\n' %
                 (escape(key), escape(defines[key])))
     out.write('    </language>\n')
@@ -418,7 +418,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     GenerateOutputForConfig(target_list, target_dicts, data, params,
                             user_config)
   else:
-    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    config_names = list(target_dicts[target_list[0]]['configurations'].keys())
     for config_name in config_names:
       GenerateOutputForConfig(target_list, target_dicts, data, params,
                               config_name)
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py
index 3efdb9966a..78eeaa61b2 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/gypd.py
@@ -88,7 +88,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     if not output_file in output_files:
       output_files[output_file] = input_file
 
-  for output_file, input_file in output_files.iteritems():
+  for output_file, input_file in output_files.items():
     output = open(output_file, 'w')
     pprint.pprint(data[input_file], output)
     output.close()
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py
index b7da768fb3..3339cf6b0f 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/make.py
@@ -499,7 +499,7 @@ cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES)
 
 
 def WriteRootHeaderSuffixRules(writer):
-  extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
+  extensions = sorted(list(COMPILABLE_EXTENSIONS.keys()), key=str.lower)
 
   writer.write('# Suffix rules, putting all outputs into $(obj).\n')
   for ext in extensions:
@@ -645,9 +645,9 @@ def _ValidateSourcesForOSX(spec, all_sources):
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
-      error += '  %s: %s\n' % (basename, ' '.join(files))
+      error += '  {}: {}\n'.format(basename, ' '.join(files))
 
   if error:
     print('static library %s has several files with the same basename:\n' %
@@ -665,7 +665,7 @@ target_outputs = {}
 target_link_deps = {}
 
 
-class MakefileWriter(object):
+class MakefileWriter:
   """MakefileWriter packages up the writing of one target-specific foobar.mk.
 
   Its only real entry point is Write(), and is mostly used for namespacing.
@@ -683,19 +683,19 @@ class MakefileWriter(object):
     for ext in COMPILABLE_EXTENSIONS.keys():
       # Suffix rules for source folder.
       self.suffix_rules_srcdir.update({ext: ("""\
-$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD
-	@$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%{} FORCE_DO_CMD
+	@$(call do_cmd,{},1)
+""".format(ext, COMPILABLE_EXTENSIONS[ext]))})
 
       # Suffix rules for generated source files.
       self.suffix_rules_objdir1.update({ext: ("""\
-$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD
-	@$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%{} FORCE_DO_CMD
+	@$(call do_cmd,{},1)
+""".format(ext, COMPILABLE_EXTENSIONS[ext]))})
       self.suffix_rules_objdir2.update({ext: ("""\
-$(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
-	@$(call do_cmd,%s,1)
-""" % (ext, COMPILABLE_EXTENSIONS[ext]))})
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%{} FORCE_DO_CMD
+	@$(call do_cmd,{},1)
+""".format(ext, COMPILABLE_EXTENSIONS[ext]))})
 
 
   def Write(self, qualified_target, base_path, output_filename, spec, configs,
@@ -793,10 +793,10 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
           gyp.xcode_emulation.MacPrefixHeader(
               self.xcode_settings, lambda p: Sourceify(self.Absolutify(p)),
               self.Pchify))
-      sources = filter(Compilable, all_sources)
+      sources = list(filter(Compilable, all_sources))
       if sources:
         self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
-        extensions = set([os.path.splitext(s)[1] for s in sources])
+        extensions = {os.path.splitext(s)[1] for s in sources}
         for ext in extensions:
           if ext in self.suffix_rules_srcdir:
             self.WriteLn(self.suffix_rules_srcdir[ext])
@@ -854,7 +854,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     self.WriteLn('all:')
     if makefile_path:
       makefile_path = ' -C ' + makefile_path
-    self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
+    self.WriteLn('\t$(MAKE){} {}'.format(makefile_path, ' '.join(targets)))
     self.fp.close()
 
 
@@ -871,7 +871,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     """
     env = self.GetSortedXcodeEnv()
     for action in actions:
-      name = StringToMakefileVariable('%s_%s' % (self.qualified_target,
+      name = StringToMakefileVariable('{}_{}'.format(self.qualified_target,
                                                  action['action_name']))
       self.WriteLn('### Rules for action "%s":' % action['action_name'])
       inputs = action['inputs']
@@ -896,9 +896,9 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
                           for command in action_commands]
       command = gyp.common.EncodePOSIXShellList(action_commands)
       if 'message' in action:
-        self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message']))
+        self.WriteLn('quiet_cmd_{} = ACTION {} $@'.format(name, action['message']))
       else:
-        self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
+        self.WriteLn('quiet_cmd_{} = ACTION {} $@'.format(name, name))
       if len(dirs) > 0:
         command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
 
@@ -922,7 +922,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
                    '%s%s'
                    % (name, cd_action, command))
       self.WriteLn()
-      outputs = map(self.Absolutify, outputs)
+      outputs = list(map(self.Absolutify, outputs))
       # The makefile rules are all relative to the top dir, but the gyp actions
       # are defined relative to their containing dir.  This replaces the obj
       # variable for the action rule with an absolute version so that the output
@@ -946,12 +946,12 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
       inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
 
-      self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
+      self.WriteDoCmd(outputs, list(map(Sourceify, list(map(self.Absolutify, inputs)))),
                       part_of_all=part_of_all, command=name)
 
       # Stuff the outputs in a variable so we can refer to them later.
       outputs_variable = 'action_%s_outputs' % name
-      self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs)))
+      self.WriteLn('{} := {}'.format(outputs_variable, ' '.join(outputs)))
       extra_outputs.append('$(%s)' % outputs_variable)
       self.WriteLn()
 
@@ -970,7 +970,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     """
     env = self.GetSortedXcodeEnv()
     for rule in rules:
-      name = StringToMakefileVariable('%s_%s' % (self.qualified_target,
+      name = StringToMakefileVariable('{}_{}'.format(self.qualified_target,
                                                  rule['rule_name']))
       count = 0
       self.WriteLn('### Generated for rule %s:' % name)
@@ -995,8 +995,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
           extra_sources += outputs
         if int(rule.get('process_outputs_as_mac_bundle_resources', False)):
           extra_mac_bundle_resources += outputs
-        inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
-                                    rule.get('inputs', [])))
+        inputs = list(map(Sourceify, list(map(self.Absolutify, [rule_source] +
+                                    rule.get('inputs', [])))))
         actions = ['$(call do_cmd,%s_%d)' % (name, count)]
 
         if name == 'resources_grit':
@@ -1012,7 +1012,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
         inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
 
-        outputs = map(self.Absolutify, outputs)
+        outputs = list(map(self.Absolutify, outputs))
         all_outputs += outputs
         # Only write the 'obj' and 'builddir' rules for the "primary" output
         # (:1); it's superfluous for the "extra outputs", and this avoids
@@ -1119,7 +1119,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         path = gyp.xcode_emulation.ExpandEnvVars(path, env)
         self.WriteDoCmd([output], [path], 'copy', part_of_all)
         outputs.append(output)
-    self.WriteLn('%s = %s' % (variable, ' '.join(map(QuoteSpaces, outputs))))
+    self.WriteLn('{} = {}'.format(variable, ' '.join(map(QuoteSpaces, outputs))))
     extra_outputs.append('$(%s)' % variable)
     self.WriteLn()
 
@@ -1130,7 +1130,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
 
     for output, res in gyp.xcode_emulation.GetMacBundleResources(
         generator_default_variables['PRODUCT_DIR'], self.xcode_settings,
-        map(Sourceify, map(self.Absolutify, resources))):
+        list(map(Sourceify, list(map(self.Absolutify, resources))))):
       _, ext = os.path.splitext(output)
       if ext != '.xcassets':
         # Make does not supports '.xcassets' emulation.
@@ -1210,11 +1210,11 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         self.WriteList(cflags_objcc, 'CFLAGS_OBJCC_%s' % configname)
       includes = config.get('include_dirs')
       if includes:
-        includes = map(Sourceify, map(self.Absolutify, includes))
+        includes = list(map(Sourceify, list(map(self.Absolutify, includes))))
       self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
 
-    compilable = filter(Compilable, sources)
-    objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
+    compilable = list(filter(Compilable, sources))
+    objs = list(map(self.Objectify, list(map(self.Absolutify, list(map(Target, compilable))))))
     self.WriteList(objs, 'OBJS')
 
     for obj in objs:
@@ -1245,7 +1245,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     if pchdeps:
       self.WriteLn('# Dependencies from obj files to their precompiled headers')
       for source, obj, gch in pchdeps:
-        self.WriteLn('%s: %s' % (obj, gch))
+        self.WriteLn('{}: {}'.format(obj, gch))
       self.WriteLn('# End precompiled header dependencies')
 
     if objs:
@@ -1286,7 +1286,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
 
     # If there are any object files in our input file list, link them into our
     # output.
-    extra_link_deps += filter(Linkable, sources)
+    extra_link_deps += list(filter(Linkable, sources))
 
     self.WriteLn()
 
@@ -1308,13 +1308,13 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         'm': 'GYP_PCH_OBJCFLAGS',
         'mm': 'GYP_PCH_OBJCXXFLAGS',
       }[lang]
-      self.WriteLn("%s: %s := %s " % (gch, var_name, lang_flag) +
+      self.WriteLn("{}: {} := {} ".format(gch, var_name, lang_flag) +
                    "$(DEFS_$(BUILDTYPE)) "
                    "$(INCS_$(BUILDTYPE)) "
                    "$(CFLAGS_$(BUILDTYPE)) " +
                    extra_flags)
 
-      self.WriteLn('%s: %s FORCE_DO_CMD' % (gch, input))
+      self.WriteLn('{}: {} FORCE_DO_CMD'.format(gch, input))
       self.WriteLn('\t@$(call do_cmd,pch_%s,1)' % lang)
       self.WriteLn('')
       assert ' ' not in gch, (
@@ -1351,8 +1351,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     elif self.type == 'none':
       target = '%s.stamp' % target
     elif self.type != 'executable':
-      print ("ERROR: What output file should be generated?",
-             "type", self.type, "target", target)
+      print(("ERROR: What output file should be generated?",
+             "type", self.type, "target", target))
 
     target_prefix = spec.get('product_prefix', target_prefix)
     target = spec.get('product_name', target)
@@ -1516,11 +1516,11 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       # Postbuilds expect to be run in the gyp file's directory, so insert an
       # implicit postbuild to cd to there.
       postbuilds.insert(0, gyp.common.EncodePOSIXShellList(['cd', self.path]))
-      for i in xrange(len(postbuilds)):
+      for i in range(len(postbuilds)):
         if not postbuilds[i].startswith('$'):
           postbuilds[i] = EscapeShellArgument(postbuilds[i])
       self.WriteLn('%s: builddir := $(abs_builddir)' % QuoteSpaces(self.output))
-      self.WriteLn('%s: POSTBUILDS := %s' % (
+      self.WriteLn('{}: POSTBUILDS := {}'.format(
           QuoteSpaces(self.output), ' '.join(postbuilds)))
 
     # A bundle directory depends on its dependencies such as bundle resources
@@ -1533,7 +1533,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
 
       # Bundle dependencies. Note that the code below adds actions to this
       # target, so if you move these two lines, move the lines below as well.
-      self.WriteList(map(QuoteSpaces, bundle_deps), 'BUNDLE_DEPS')
+      self.WriteList(list(map(QuoteSpaces, bundle_deps)), 'BUNDLE_DEPS')
       self.WriteLn('%s: $(BUNDLE_DEPS)' % QuoteSpaces(self.output))
 
       # After the framework is built, package it. Needs to happen before
@@ -1565,7 +1565,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
           'custom product_dir')
 
     if self.type == 'executable':
-      self.WriteLn('%s: LD_INPUTS := %s' % (
+      self.WriteLn('{}: LD_INPUTS := {}'.format(
           QuoteSpaces(self.output_binary),
           ' '.join(map(QuoteSpaces, link_deps))))
       if self.toolset == 'host' and self.flavor == 'android':
@@ -1587,7 +1587,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         self.WriteDoCmd([self.output_binary], link_deps, 'alink', part_of_all,
                         postbuilds=postbuilds)
     elif self.type == 'shared_library':
-      self.WriteLn('%s: LD_INPUTS := %s' % (
+      self.WriteLn('{}: LD_INPUTS := {}'.format(
             QuoteSpaces(self.output_binary),
             ' '.join(map(QuoteSpaces, link_deps))))
       self.WriteDoCmd([self.output_binary], link_deps, 'solink', part_of_all,
@@ -1608,7 +1608,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       self.WriteDoCmd([self.output_binary], deps, 'touch', part_of_all,
                       postbuilds=postbuilds)
     else:
-      print "WARNING: no output for", self.type, target
+      print("WARNING: no output for", self.type, target)
 
     # Add an alias for each target (if there are any outputs).
     # Installable target aliases are created below.
@@ -1638,7 +1638,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       if (self.flavor == 'mac' and not 'product_dir' in spec and
           self.toolset == 'target'):
         # On mac, products are created in install_path immediately.
-        assert install_path == self.output, '%s != %s' % (
+        assert install_path == self.output, '{} != {}'.format(
             install_path, self.output)
 
       # Point the target alias to the final binary output.
@@ -1672,7 +1672,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     if value_list:
       value_list = [quoter(prefix + l) for l in value_list]
       values = ' \\\n\t' + ' \\\n\t'.join(value_list)
-    self.fp.write('%s :=%s\n\n' % (variable, values))
+    self.fp.write('{} :={}\n\n'.format(variable, values))
 
 
   def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None,
@@ -1687,7 +1687,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       assert ',' not in command
       suffix = ',,1'  # Tell do_cmd to honor $POSTBUILDS
     self.WriteMakeRule(outputs, inputs,
-                       actions = ['$(call do_cmd,%s%s)' % (command, suffix)],
+                       actions = ['$(call do_cmd,{}{})'.format(command, suffix)],
                        comment = comment,
                        command = command,
                        force = True)
@@ -1715,8 +1715,8 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
            output is just a name to run the rule
     command: (optional) command name to generate unambiguous labels
     """
-    outputs = map(QuoteSpaces, outputs)
-    inputs = map(QuoteSpaces, inputs)
+    outputs = list(map(QuoteSpaces, outputs))
+    inputs = list(map(QuoteSpaces, inputs))
 
     if comment:
       self.WriteLn('# ' + comment)
@@ -1733,7 +1733,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
                    (' '.join(outputs), ' '.join(inputs), force_append))
     elif len(outputs) == 1:
       # Regular rule, one output: Just write a simple rule.
-      self.WriteLn('%s: %s%s' % (outputs[0], ' '.join(inputs), force_append))
+      self.WriteLn('{}: {}{}'.format(outputs[0], ' '.join(inputs), force_append))
     else:
       # Regular rule, more than one output: Multiple outputs are tricky in
       # make. We will write three rules:
@@ -1744,9 +1744,9 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       # - The intermediate recipe will 'touch' the intermediate file.
       # - The multi-output rule will have an do-nothing recipe.
       intermediate = "%s.intermediate" % (command if command else self.target)
-      self.WriteLn('%s: %s' % (' '.join(outputs), intermediate))
+      self.WriteLn('{}: {}'.format(' '.join(outputs), intermediate))
       self.WriteLn('\t%s' % '@:');
-      self.WriteLn('%s: %s' % ('.INTERMEDIATE', intermediate))
+      self.WriteLn('{}: {}'.format('.INTERMEDIATE', intermediate))
       self.WriteLn('%s: %s%s' %
                    (intermediate, ' '.join(inputs), force_append))
       actions.insert(0, '$(call do_cmd,touch)')
@@ -1802,7 +1802,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
           default_cpp_ext = ext
     self.WriteLn('LOCAL_CPP_EXTENSION := ' + default_cpp_ext)
 
-    self.WriteList(map(self.Absolutify, filter(Compilable, all_sources)),
+    self.WriteList(list(map(self.Absolutify, list(filter(Compilable, all_sources)))),
                    'LOCAL_SRC_FILES')
 
     # Filter out those which do not match prefix and suffix and produce
@@ -1870,7 +1870,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       #  export foo := a\ b
       # it does not -- the backslash is written to the env as literal character.
       # So don't escape spaces in |env[k]|.
-      self.WriteLn('%s: export %s := %s' % (QuoteSpaces(target), k, v))
+      self.WriteLn('{}: export {} := {}'.format(QuoteSpaces(target), k, v))
 
 
   def Objectify(self, path):
@@ -1878,7 +1878,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
     if '$(' in path:
       path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
     if not '$(obj)' in path:
-      path = '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
+      path = '$(obj).{}/$(TARGET)/{}'.format(self.toolset, path)
     return path
 
 
@@ -1889,7 +1889,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
       path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/pch-%s' %
                           (self.toolset, lang))
       return path
-    return '$(obj).%s/$(TARGET)/pch-%s/%s' % (self.toolset, lang, path)
+    return '$(obj).{}/$(TARGET)/pch-{}/{}'.format(self.toolset, lang, path)
 
 
   def Absolutify(self, path):
@@ -1921,7 +1921,7 @@ $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
         (self.flavor != 'mac' or self.toolset != 'target')):
       # Install all shared libs into a common directory (per toolset) for
       # convenient access with LD_LIBRARY_PATH.
-      return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias)
+      return '$(builddir)/lib.{}/{}'.format(self.toolset, self.alias)
     return '$(builddir)/' + self.alias
 
 
@@ -1957,7 +1957,7 @@ def PerformBuild(data, configurations, params):
     if options.toplevel_dir and options.toplevel_dir != '.':
       arguments += '-C', options.toplevel_dir
     arguments.append('BUILDTYPE=' + config)
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [{}]: {}'.format(config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -1990,7 +1990,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
   # away when we add verification that all targets have the
   # necessary configurations.
   default_configuration = None
-  toolsets = set([target_dicts[target]['toolset'] for target in target_list])
+  toolsets = {target_dicts[target]['toolset'] for target in target_list}
   for target in target_list:
     spec = target_dicts[target]
     if spec['default_configuration'] != 'Default':
@@ -2083,7 +2083,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
       value = '$(abspath %s)' % value
     wrapper = wrappers.get(key)
     if wrapper:
-      value = '%s %s' % (wrapper, value)
+      value = '{} {}'.format(wrapper, value)
       del wrappers[key]
     if key in ('CC', 'CC.host', 'CXX', 'CXX.host'):
       make_global_settings += (
@@ -2092,10 +2092,10 @@ def GenerateOutput(target_list, target_dicts, data, params):
       env_key = key.replace('.', '_')  # CC.host -> CC_host
       if env_key in os.environ:
         value = os.environ[env_key]
-      make_global_settings += '  %s = %s\n' % (key, value)
+      make_global_settings += '  {} = {}\n'.format(key, value)
       make_global_settings += 'endif\n'
     else:
-      make_global_settings += '%s ?= %s\n' % (key, value)
+      make_global_settings += '{} ?= {}\n'.format(key, value)
   # TODO(ukai): define cmd when only wrapper is specified in
   # make_global_settings.
 
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py
index 7924aa1bcf..f57bad9731 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/msvs.py
@@ -291,7 +291,7 @@ def _ConfigBaseName(config_name, platform_name):
 
 def _ConfigFullName(config_name, config_data):
   platform_name = _ConfigPlatform(config_data)
-  return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
+  return '{}|{}'.format(_ConfigBaseName(config_name, platform_name), platform_name)
 
 
 def _ConfigWindowsTargetPlatformVersion(config_data):
@@ -457,7 +457,7 @@ def _AddCustomBuildToolForMSVS(p, spec, primary_input,
        'CommandLine': cmd,
       })
   # Add to the properties of primary input for each config.
-  for config_name, c_data in spec['configurations'].iteritems():
+  for config_name, c_data in spec['configurations'].items():
     p.AddFileConfig(_FixPath(primary_input),
                     _ConfigFullName(config_name, c_data), tools=[tool])
 
@@ -554,7 +554,7 @@ def _GenerateNativeRulesForMSVS(p, rules, output_dir, spec, options):
     spec: the project dict
     options: global generator options
   """
-  rules_filename = '%s%s.rules' % (spec['target_name'],
+  rules_filename = '{}{}.rules'.format(spec['target_name'],
                                    options.suffix)
   rules_file = MSVSToolFile.Writer(os.path.join(output_dir, rules_filename),
                                    spec['target_name'])
@@ -600,7 +600,7 @@ def _GenerateExternalRules(rules, output_dir, spec,
     options: global generator options
     actions_to_add: The list of actions we will add to.
   """
-  filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix)
+  filename = '{}_rules{}.mk'.format(spec['target_name'], options.suffix)
   mk_file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename))
   # Find cygwin style versions of some paths.
   mk_file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n')
@@ -643,7 +643,7 @@ def _GenerateExternalRules(rules, output_dir, spec,
       cmd = ['"%s"' % i for i in cmd]
       cmd = ' '.join(cmd)
       # Add it to the makefile.
-      mk_file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs)))
+      mk_file.write('{}: {}\n'.format(' '.join(outputs), ' '.join(inputs)))
       mk_file.write('\t%s\n\n' % cmd)
   # Close up the file.
   mk_file.close()
@@ -763,8 +763,8 @@ def _EscapeVCProjCommandLineArgListItem(s):
     # the VCProj but cause the same problem on the final command-line. Moving
     # the item to the end of the list does works, but that's only possible if
     # there's only one such item. Let's just warn the user.
-    print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' +
-                          'quotes in ' + s)
+    print(('Warning: MSVS may misinterpret the odd number of ' +
+                          'quotes in ' + s), file=sys.stderr)
   return s
 
 
@@ -878,7 +878,7 @@ def _FilterActionsFromExcluded(excluded_sources, actions_to_add):
   Returns:
     excluded_sources with files that have actions attached removed.
   """
-  must_keep = OrderedSet(_FixPaths(actions_to_add.keys()))
+  must_keep = OrderedSet(_FixPaths(list(actions_to_add.keys())))
   return [s for s in excluded_sources if s not in must_keep]
 
 
@@ -979,9 +979,9 @@ def _ValidateSourcesForMSVSProject(spec, version):
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
-      error += '  %s: %s\n' % (basename, ' '.join(files))
+      error += '  {}: {}\n'.format(basename, ' '.join(files))
 
   if error:
     print('static library %s has several files with the same basename:\n' %
@@ -1011,7 +1011,7 @@ def _GenerateMSVSProject(project, options, version, generator_flags):
   relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, project_dir)
 
   config_type = _GetMSVSConfigurationType(spec, project.build_file)
-  for config_name, config in spec['configurations'].iteritems():
+  for config_name, config in spec['configurations'].items():
     _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config)
 
   # MSVC08 and prior version cannot handle duplicate basenames in the same
@@ -1380,10 +1380,10 @@ def _ConvertToolsToExpectedForm(tools):
     A list of Tool objects.
   """
   tool_list = []
-  for tool, settings in tools.iteritems():
+  for tool, settings in tools.items():
     # Collapse settings with lists.
     settings_fixed = {}
-    for setting, value in settings.iteritems():
+    for setting, value in settings.items():
       if type(value) == list:
         if ((tool == 'VCLinkerTool' and
              setting == 'AdditionalDependencies') or
@@ -1530,7 +1530,7 @@ def _AdjustSourcesAndConvertToFilterHierarchy(
   # such as ../../src/modules/module1 etc.
   if version.UsesVcxproj():
     while all([isinstance(s, MSVSProject.Filter) for s in sources]) \
-        and len(set([s.name for s in sources])) == 1:
+        and len({s.name for s in sources}) == 1:
       assert all([len(s.contents) == 1 for s in sources])
       sources = [s.contents[0] for s in sources]
   else:
@@ -1558,7 +1558,7 @@ def _IdlFilesHandledNonNatively(spec, sources):
 def _GetPrecompileRelatedFiles(spec):
   # Gather a list of precompiled header related sources.
   precompiled_related = []
-  for _, config in spec['configurations'].iteritems():
+  for _, config in spec['configurations'].items():
     for k in precomp_keys:
       f = config.get(k)
       if f:
@@ -1569,7 +1569,7 @@ def _GetPrecompileRelatedFiles(spec):
 def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl,
                                 list_excluded):
   exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
-  for file_name, excluded_configs in exclusions.iteritems():
+  for file_name, excluded_configs in exclusions.items():
     if (not list_excluded and
             len(excluded_configs) == len(spec['configurations'])):
       # If we're not listing excluded files, then they won't appear in the
@@ -1586,7 +1586,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
   # Exclude excluded sources from being built.
   for f in excluded_sources:
     excluded_configs = []
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       precomped = [_FixPath(config.get(i, '')) for i in precomp_keys]
       # Don't do this for ones that are precompiled header related.
       if f not in precomped:
@@ -1596,7 +1596,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
   # Exclude them now.
   for f in excluded_idl:
     excluded_configs = []
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       excluded_configs.append((config_name, config))
     exclusions[f] = excluded_configs
   return exclusions
@@ -1605,7 +1605,7 @@ def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
 def _AddToolFilesToMSVS(p, spec):
   # Add in tool files (rules).
   tool_files = OrderedSet()
-  for _, config in spec['configurations'].iteritems():
+  for _, config in spec['configurations'].items():
     for f in config.get('msvs_tool_files', []):
       tool_files.add(f)
   for f in tool_files:
@@ -1618,7 +1618,7 @@ def _HandlePreCompiledHeaders(p, sources, spec):
   # kind (i.e. C vs. C++) as the precompiled header source stub needs
   # to have use of precompiled headers disabled.
   extensions_excluded_from_precompile = []
-  for config_name, config in spec['configurations'].iteritems():
+  for config_name, config in spec['configurations'].items():
     source = config.get('msvs_precompiled_source')
     if source:
       source = _FixPath(source)
@@ -1639,7 +1639,7 @@ def _HandlePreCompiledHeaders(p, sources, spec):
       else:
         basename, extension = os.path.splitext(source)
         if extension in extensions_excluded_from_precompile:
-          for config_name, config in spec['configurations'].iteritems():
+          for config_name, config in spec['configurations'].items():
             tool = MSVSProject.Tool('VCCLCompilerTool',
                                     {'UsePrecompiledHeader': '0',
                                      'ForcedIncludeFiles': '$(NOINHERIT)'})
@@ -1690,7 +1690,7 @@ def _WriteMSVSUserFile(project_path, version, spec):
     return  # Nothing to add
   # Write out the user file.
   user_file = _CreateMSVSUserFile(project_path, version, spec)
-  for config_name, c_data in spec['configurations'].iteritems():
+  for config_name, c_data in spec['configurations'].items():
     user_file.AddDebugSettings(_ConfigFullName(config_name, c_data),
                                action, environment, working_directory)
   user_file.WriteIfChanged()
@@ -1715,14 +1715,14 @@ def _GetCopies(spec):
         src_bare = src[:-1]
         base_dir = posixpath.split(src_bare)[0]
         outer_dir = posixpath.split(src_bare)[1]
-        cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % (
+        cmd = 'cd "{}" && xcopy /e /f /y "{}" "{}\\{}\\"'.format(
             _FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir)
         copies.append(([src], ['dummy_copies', dst], cmd,
-                       'Copying %s to %s' % (src, dst)))
+                       'Copying {} to {}'.format(src, dst)))
       else:
-        cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % (
+        cmd = 'mkdir "{}" 2>nul & set ERRORLEVEL=0 & copy /Y "{}" "{}"'.format(
             _FixPath(cpy['destination']), _FixPath(src), _FixPath(dst))
-        copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst)))
+        copies.append(([src], [dst], cmd, 'Copying {} to {}'.format(src, dst)))
   return copies
 
 
@@ -1741,7 +1741,7 @@ def _GetPathDict(root, path):
 def _DictsToFolders(base_path, bucket, flat):
   # Convert to folders recursively.
   children = []
-  for folder, contents in bucket.iteritems():
+  for folder, contents in bucket.items():
     if type(contents) == dict:
       folder_children = _DictsToFolders(os.path.join(base_path, folder),
                                         contents, flat)
@@ -1763,8 +1763,8 @@ def _CollapseSingles(parent, node):
   # such projects up one level.
   if (type(node) == dict and
       len(node) == 1 and
-      node.keys()[0] == parent + '.vcproj'):
-    return node[node.keys()[0]]
+      list(node.keys())[0] == parent + '.vcproj'):
+    return node[list(node.keys())[0]]
   if type(node) != dict:
     return node
   for child in node:
@@ -1783,8 +1783,8 @@ def _GatherSolutionFolders(sln_projects, project_objects, flat):
   # Walk down from the top until we hit a folder that has more than one entry.
   # In practice, this strips the top-level "src/" dir from the hierarchy in
   # the solution.
-  while len(root) == 1 and type(root[root.keys()[0]]) == dict:
-    root = root[root.keys()[0]]
+  while len(root) == 1 and type(root[list(root.keys())[0]]) == dict:
+    root = root[list(root.keys())[0]]
   # Collapse singles.
   root = _CollapseSingles('', root)
   # Merge buckets until everything is a root entry.
@@ -1813,10 +1813,10 @@ def _GetPlatformOverridesOfProject(spec):
   # Prepare a dict indicating which project configurations are used for which
   # solution configurations for this target.
   config_platform_overrides = {}
-  for config_name, c in spec['configurations'].iteritems():
+  for config_name, c in spec['configurations'].items():
     config_fullname = _ConfigFullName(config_name, c)
     platform = c.get('msvs_target_platform', _ConfigPlatform(c))
-    fixed_config_fullname = '%s|%s' % (
+    fixed_config_fullname = '{}|{}'.format(
         _ConfigBaseName(config_name, _ConfigPlatform(c)), platform)
     config_platform_overrides[config_fullname] = fixed_config_fullname
   return config_platform_overrides
@@ -1952,7 +1952,7 @@ def PerformBuild(data, configurations, params):
   msvs_version = params['msvs_version']
   devenv = os.path.join(msvs_version.path, 'Common7', 'IDE', 'devenv.com')
 
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -1962,7 +1962,7 @@ def PerformBuild(data, configurations, params):
 
   for config in configurations:
     arguments = [devenv, sln_path, '/Build', config]
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [{}]: {}'.format(config, arguments))
     rtn = subprocess.check_call(arguments)
 
 
@@ -2014,7 +2014,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
   configs = set()
   for qualified_target in target_list:
     spec = target_dicts[qualified_target]
-    for config_name, config in spec['configurations'].iteritems():
+    for config_name, config in spec['configurations'].items():
       configs.add(_ConfigFullName(config_name, config))
   configs = list(configs)
 
@@ -2057,7 +2057,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     if generator_flags.get('msvs_error_on_missing_sources', False):
       raise GypError(error_message)
     else:
-      print >> sys.stdout, "Warning: " + error_message
+      print("Warning: " + error_message, file=sys.stdout)
 
 
 def _GenerateMSBuildFiltersFile(filters_path, source_files,
@@ -2109,7 +2109,7 @@ def _AppendFiltersForMSBuild(parent_filter_name, sources, rule_dependencies,
       if not parent_filter_name:
         filter_name = source.name
       else:
-        filter_name = '%s\\%s' % (parent_filter_name, source.name)
+        filter_name = '{}\\{}'.format(parent_filter_name, source.name)
       # Add the filter to the group.
       filter_group.append(
           ['Filter', {'Include': filter_name},
@@ -2213,7 +2213,7 @@ def _GenerateRulesForMSBuild(output_dir, options, spec,
   _AdjustSourcesForRules(rules, sources, excluded_sources, True)
 
 
-class MSBuildRule(object):
+class MSBuildRule:
   """Used to store information used to generate an MSBuild rule.
 
   Attributes:
@@ -2373,7 +2373,7 @@ def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
         {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
          "'true'" % (rule.tlog, rule.tlog),
          'File': '$(IntDir)$(ProjectName).write.1.tlog',
-         'Lines': "^%%(%s.Source);@(%s->'%%(Fullpath)')" % (rule.tlog,
+         'Lines': "^%({}.Source);@({}->'%(Fullpath)')".format(rule.tlog,
                                                             rule.tlog)
         }
     ]
@@ -2382,7 +2382,7 @@ def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
         {'Condition': "'@(%s)' != '' and '%%(%s.ExcludedFromBuild)' != "
          "'true'" % (rule.tlog, rule.tlog),
          'File': '$(IntDir)$(ProjectName).read.1.tlog',
-         'Lines': "^%%(%s.Source);%%(%s.Inputs)" % (rule.tlog, rule.tlog)
+         'Lines': "^%({}.Source);%({}.Inputs)".format(rule.tlog, rule.tlog)
         }
     ]
     command_and_input_section = [
@@ -2403,7 +2403,7 @@ def _GenerateMSBuildRuleTargetsFile(targets_path, msbuild_rules):
           'BeforeTargets': '$(%s)' % rule.before_targets,
           'AfterTargets': '$(%s)' % rule.after_targets,
           'Condition': "'@(%s)' != ''" % rule_name,
-          'DependsOnTargets': '$(%s);%s' % (rule.depends_on,
+          'DependsOnTargets': '$({});{}'.format(rule.depends_on,
                                             rule.compute_output),
           'Outputs': target_outputs,
           'Inputs': target_inputs
@@ -2654,9 +2654,9 @@ def _GetConfigurationCondition(name, settings):
 
 def _GetMSBuildProjectConfigurations(configurations):
   group = ['ItemGroup', {'Label': 'ProjectConfigurations'}]
-  for (name, settings) in sorted(configurations.iteritems()):
+  for (name, settings) in sorted(configurations.items()):
     configuration, platform = _GetConfigurationAndPlatform(name, settings)
-    designation = '%s|%s' % (configuration, platform)
+    designation = '{}|{}'.format(configuration, platform)
     group.append(
         ['ProjectConfiguration', {'Include': designation},
          ['Configuration', configuration],
@@ -2706,7 +2706,7 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
 
   platform_name = None
   msvs_windows_sdk_version = None
-  for configuration in spec['configurations'].itervalues():
+  for configuration in spec['configurations'].values():
     platform_name = platform_name or _ConfigPlatform(configuration)
     msvs_windows_sdk_version = (msvs_windows_sdk_version or
                     _ConfigWindowsTargetPlatformVersion(configuration))
@@ -2724,7 +2724,7 @@ def _GetMSBuildGlobalProperties(spec, guid, gyp_file_name):
 
 def _GetMSBuildConfigurationDetails(spec, build_file):
   properties = {}
-  for name, settings in spec['configurations'].iteritems():
+  for name, settings in spec['configurations'].items():
     msbuild_attributes = _GetMSBuildAttributes(spec, settings, build_file)
     condition = _GetConfigurationCondition(name, settings)
     character_set = msbuild_attributes.get('CharacterSet')
@@ -2758,9 +2758,9 @@ def _GetMSBuildPropertySheets(configurations):
   user_props = r'$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props'
   additional_props = {}
   props_specified = False
-  for name, settings in sorted(configurations.iteritems()):
+  for name, settings in sorted(configurations.items()):
     configuration = _GetConfigurationCondition(name, settings)
-    if settings.has_key('msbuild_props'):
+    if 'msbuild_props' in settings:
       additional_props[configuration] = _FixPaths(settings['msbuild_props'])
       props_specified = True
     else:
@@ -2780,7 +2780,7 @@ def _GetMSBuildPropertySheets(configurations):
     ]
   else:
     sheets = []
-    for condition, props in additional_props.iteritems():
+    for condition, props in additional_props.items():
       import_group = [
         'ImportGroup',
         {'Label': 'PropertySheets',
@@ -2813,7 +2813,7 @@ def _ConvertMSVSBuildAttributes(spec, config, build_file):
     elif a == 'ConfigurationType':
       msbuild_attributes[a] = _ConvertMSVSConfigurationType(msvs_attributes[a])
     else:
-      print 'Warning: Do not know how to convert MSVS attribute ' + a
+      print('Warning: Do not know how to convert MSVS attribute ' + a)
   return msbuild_attributes
 
 
@@ -2906,7 +2906,7 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
       new_paths = '$(ExecutablePath);' + ';'.join(new_paths)
 
   properties = {}
-  for (name, configuration) in sorted(configurations.iteritems()):
+  for (name, configuration) in sorted(configurations.items()):
     condition = _GetConfigurationCondition(name, configuration)
     attributes = _GetMSBuildAttributes(spec, configuration, build_file)
     msbuild_settings = configuration['finalized_msbuild_settings']
@@ -2928,7 +2928,7 @@ def _GetMSBuildConfigurationGlobalProperties(spec, configurations, build_file):
       _AddConditionalProperty(properties, condition, 'ExecutablePath',
                               new_paths)
     tool_settings = msbuild_settings.get('', {})
-    for name, value in sorted(tool_settings.iteritems()):
+    for name, value in sorted(tool_settings.items()):
       formatted_value = _GetValueFormattedForMSBuild('', name, value)
       _AddConditionalProperty(properties, condition, name, formatted_value)
   return _GetMSBuildPropertyGroup(spec, None, properties)
@@ -2986,18 +2986,18 @@ def _GetMSBuildPropertyGroup(spec, label, properties):
       #
       # Self references are ignored. Self reference is used in a few places to
       # append to the default value. I.e. PATH=$(PATH);other_path
-      edges.update(set([v for v in MSVS_VARIABLE_REFERENCE.findall(value)
-                        if v in properties and v != node]))
+      edges.update({v for v in MSVS_VARIABLE_REFERENCE.findall(value)
+                        if v in properties and v != node})
     return edges
   properties_ordered = gyp.common.TopologicallySorted(
-      properties.keys(), GetEdges)
+      list(properties.keys()), GetEdges)
   # Walk properties in the reverse of a topological sort on
   # user_of_variable -> used_variable as this ensures variables are
   # defined before they are used.
   # NOTE: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
   for name in reversed(properties_ordered):
     values = properties[name]
-    for value, conditions in sorted(values.iteritems()):
+    for value, conditions in sorted(values.items()):
       if len(conditions) == num_configurations:
         # If the value is the same all configurations,
         # just add one unconditional entry.
@@ -3010,18 +3010,18 @@ def _GetMSBuildPropertyGroup(spec, label, properties):
 
 def _GetMSBuildToolSettingsSections(spec, configurations):
   groups = []
-  for (name, configuration) in sorted(configurations.iteritems()):
+  for (name, configuration) in sorted(configurations.items()):
     msbuild_settings = configuration['finalized_msbuild_settings']
     group = ['ItemDefinitionGroup',
              {'Condition': _GetConfigurationCondition(name, configuration)}
             ]
-    for tool_name, tool_settings in sorted(msbuild_settings.iteritems()):
+    for tool_name, tool_settings in sorted(msbuild_settings.items()):
       # Skip the tool named '' which is a holder of global settings handled
       # by _GetMSBuildConfigurationGlobalProperties.
       if tool_name:
         if tool_settings:
           tool = [tool_name]
-          for name, value in sorted(tool_settings.iteritems()):
+          for name, value in sorted(tool_settings.items()):
             formatted_value = _GetValueFormattedForMSBuild(tool_name, name,
                                                            value)
             tool.append([name, formatted_value])
@@ -3054,7 +3054,7 @@ def _FinalizeMSBuildSettings(spec, configuration):
     for ignored_setting in ignored_settings:
       value = configuration.get(ignored_setting)
       if value:
-        print ('Warning: The automatic conversion to MSBuild does not handle '
+        print('Warning: The automatic conversion to MSBuild does not handle '
                '%s.  Ignoring setting of %s' % (ignored_setting, str(value)))
 
   defines = [_EscapeCppDefineForMSBuild(d) for d in defines]
@@ -3221,7 +3221,7 @@ def _AddSources2(spec, sources, exclusions, grouped_sources,
                            {'Condition': condition},
                            'true'])
         # Add precompile if needed
-        for config_name, configuration in spec['configurations'].iteritems():
+        for config_name, configuration in spec['configurations'].items():
           precompiled_source = configuration.get('msvs_precompiled_source', '')
           if precompiled_source != '':
             precompiled_source = _FixPath(precompiled_source)
@@ -3267,7 +3267,7 @@ def _GetMSBuildProjectReferences(project):
           ['Project', guid],
           ['ReferenceOutputAssembly', 'false']
           ]
-      for config in dependency.spec.get('configurations', {}).itervalues():
+      for config in dependency.spec.get('configurations', {}).values():
         # If it's disabled in any config, turn it off in the reference.
         if config.get('msvs_2010_disable_uldi_when_referenced', 0):
           project_ref.append(['UseLibraryDependencyInputs', 'false'])
@@ -3333,7 +3333,7 @@ def _GenerateMSBuildProject(project, options, version, generator_flags):
                               extension_to_rule_name)
   missing_sources = _VerifySourcesExist(sources, project_dir)
 
-  for configuration in configurations.itervalues():
+  for configuration in configurations.values():
     _FinalizeMSBuildSettings(spec, configuration)
 
   # Add attributes to root element
@@ -3458,7 +3458,7 @@ def _GenerateActionsForMSBuild(spec, actions_to_add):
   """
   sources_handled_by_action = OrderedSet()
   actions_spec = []
-  for primary_input, actions in actions_to_add.iteritems():
+  for primary_input, actions in actions_to_add.items():
     inputs = OrderedSet()
     outputs = OrderedSet()
     descriptions = []
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py
index 0555a4a90d..ef8549771c 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/ninja.py
@@ -95,10 +95,10 @@ def Define(d, flavor):
 def AddArch(output, arch):
   """Adds an arch string to an output path."""
   output, extension = os.path.splitext(output)
-  return '%s.%s%s' % (output, arch, extension)
+  return '{}.{}{}'.format(output, arch, extension)
 
 
-class Target(object):
+class Target:
   """Target represents the paths used within a single gyp target.
 
   Conceptually, building a single target A is a series of steps:
@@ -208,7 +208,7 @@ class Target(object):
 #   an output file; the result can be namespaced such that it is unique
 #   to the input file name as well as the output target name.
 
-class NinjaWriter(object):
+class NinjaWriter:
   def __init__(self, hash_for_rules, target_outputs, base_dir, build_dir,
                output_file, toplevel_build, output_file_name, flavor,
                toplevel_dir=None):
@@ -350,7 +350,7 @@ class NinjaWriter(object):
 
     Uses a stamp file if necessary."""
 
-    assert targets == filter(None, targets), targets
+    assert targets == [_f for _f in targets if _f], targets
     if len(targets) == 0:
       assert not order_only
       return None
@@ -362,7 +362,7 @@ class NinjaWriter(object):
 
   def _SubninjaNameForArch(self, arch):
     output_file_base = os.path.splitext(self.output_file_name)[0]
-    return '%s.%s.ninja' % (output_file_base, arch)
+    return '{}.{}.ninja'.format(output_file_base, arch)
 
   def WriteSpec(self, spec, config_name, generator_flags):
     """The main entry point for NinjaWriter: write the build rules for a spec.
@@ -403,12 +403,12 @@ class NinjaWriter(object):
     if self.flavor == 'mac':
       self.archs = self.xcode_settings.GetActiveArchs(config_name)
       if len(self.archs) > 1:
-        self.arch_subninjas = dict(
-            (arch, ninja_syntax.Writer(
+        self.arch_subninjas = {
+            arch: ninja_syntax.Writer(
                 OpenOutput(os.path.join(self.toplevel_build,
                                         self._SubninjaNameForArch(arch)),
-                           'w')))
-            for arch in self.archs)
+                           'w'))
+            for arch in self.archs}
 
     # Compute predepends for all rules.
     # actions_depends is the dependencies this target depends on before running
@@ -427,8 +427,8 @@ class NinjaWriter(object):
           compile_depends.append(target.PreCompileInput())
           if target.uses_cpp:
             self.target.uses_cpp = True
-      actions_depends = filter(None, actions_depends)
-      compile_depends = filter(None, compile_depends)
+      actions_depends = [_f for _f in actions_depends if _f]
+      compile_depends = [_f for _f in compile_depends if _f]
       actions_depends = self.WriteCollapsedDependencies('actions_depends',
                                                         actions_depends)
       compile_depends = self.WriteCollapsedDependencies('compile_depends',
@@ -455,8 +455,8 @@ class NinjaWriter(object):
     try:
       sources = extra_sources + spec.get('sources', [])
     except TypeError:
-      print 'extra_sources: ', str(extra_sources)
-      print 'spec.get("sources"): ', str(spec.get('sources'))
+      print('extra_sources: ', str(extra_sources))
+      print('spec.get("sources"): ', str(spec.get('sources')))
       raise
     if sources:
       if self.flavor == 'mac' and len(self.archs) > 1:
@@ -485,8 +485,8 @@ class NinjaWriter(object):
         if self.flavor != 'mac' or len(self.archs) == 1:
           link_deps += [self.GypPathToNinja(o) for o in obj_outputs]
         else:
-          print "Warning: Actions/rules writing object files don't work with " \
-                "multiarch targets, dropping. (target %s)" % spec['target_name']
+          print("Warning: Actions/rules writing object files don't work with " \
+                "multiarch targets, dropping. (target %s)" % spec['target_name'])
     elif self.flavor == 'mac' and len(self.archs) > 1:
       link_deps = collections.defaultdict(list)
 
@@ -544,7 +544,7 @@ class NinjaWriter(object):
     if self.msvs_settings.HasExplicitIdlRulesOrActions(spec):
       return []
     outputs = []
-    for source in filter(lambda x: x.endswith('.idl'), spec['sources']):
+    for source in [x for x in spec['sources'] if x.endswith('.idl')]:
       self._WinIdlRule(source, prebuild, outputs)
     return outputs
 
@@ -595,9 +595,9 @@ class NinjaWriter(object):
     if self.toolset != 'target':
       verb += '(%s)' % self.toolset
     if message:
-      return '%s %s' % (verb, self.ExpandSpecial(message))
+      return '{} {}'.format(verb, self.ExpandSpecial(message))
     else:
-      return '%s %s: %s' % (verb, self.name, fallback)
+      return '{} {}: {}'.format(verb, self.name, fallback)
 
   def WriteActions(self, actions, extra_sources, prebuild,
                    extra_mac_bundle_resources):
@@ -606,7 +606,7 @@ class NinjaWriter(object):
     all_outputs = []
     for action in actions:
       # First write out a rule for the action.
-      name = '%s_%s' % (action['action_name'], self.hash_for_rules)
+      name = '{}_{}'.format(action['action_name'], self.hash_for_rules)
       description = self.GenerateDescription('ACTION',
                                              action.get('message', None),
                                              name)
@@ -647,7 +647,7 @@ class NinjaWriter(object):
         continue
 
       # First write out a rule for the rule action.
-      name = '%s_%s' % (rule['rule_name'], self.hash_for_rules)
+      name = '{}_{}'.format(rule['rule_name'], self.hash_for_rules)
 
       args = rule['action']
       description = self.GenerateDescription(
@@ -667,7 +667,7 @@ class NinjaWriter(object):
       # must vary per source file.
       # Compute the list of variables we'll need to provide.
       special_locals = ('source', 'root', 'dirname', 'ext', 'name')
-      needed_variables = set(['source'])
+      needed_variables = {'source'}
       for argument in args:
         for var in special_locals:
           if '${%s}' % var in argument:
@@ -791,10 +791,10 @@ class NinjaWriter(object):
     copy_headers = spec['mac_framework_headers']
     output = self.GypPathToUniqueOutput('headers.hmap')
     self.xcode_settings.header_map_path = output
-    all_headers = map(self.GypPathToNinja,
-                      filter(lambda x:x.endswith(('.h')), all_sources))
+    all_headers = list(map(self.GypPathToNinja,
+                      [x for x in all_sources if x.endswith('.h')]))
     variables = [('framework', framework),
-                 ('copy_headers', map(self.GypPathToNinja, copy_headers))]
+                 ('copy_headers', list(map(self.GypPathToNinja, copy_headers)))]
     outputs.extend(self.ninja.build(
         output, 'compile_ios_framework_headers', all_headers,
         variables=variables, order_only=prebuild))
@@ -810,7 +810,7 @@ class NinjaWriter(object):
 
     for output, res in gyp.xcode_emulation.GetMacBundleResources(
         generator_default_variables['PRODUCT_DIR'],
-        self.xcode_settings, map(self.GypPathToNinja, resources)):
+        self.xcode_settings, list(map(self.GypPathToNinja, resources))):
       output = self.ExpandSpecial(output)
       if os.path.splitext(output)[-1] != '.xcassets':
         self.ninja.build(output, 'mac_tool', res,
@@ -838,7 +838,7 @@ class NinjaWriter(object):
         'XCASSETS_LAUNCH_IMAGE': 'launch-image',
     }
     settings = self.xcode_settings.xcode_settings[self.config_name]
-    for settings_key, arg_name in settings_to_arg.iteritems():
+    for settings_key, arg_name in settings_to_arg.items():
       value = settings.get(settings_key)
       if value:
         extra_arguments[arg_name] = value
@@ -918,10 +918,10 @@ class NinjaWriter(object):
           self.ninja, config_name, config, sources, predepends,
           precompiled_header, spec)
     else:
-      return dict((arch, self.WriteSourcesForArch(
+      return {arch: self.WriteSourcesForArch(
             self.arch_subninjas[arch], config_name, config, sources, predepends,
-            precompiled_header, spec, arch=arch))
-          for arch in self.archs)
+            precompiled_header, spec, arch=arch)
+          for arch in self.archs}
 
   def WriteSourcesForArch(self, ninja_file, config_name, config, sources,
                           predepends, precompiled_header, spec, arch=None):
@@ -978,7 +978,7 @@ class NinjaWriter(object):
                            [Define(d, self.flavor) for d in defines])
     if self.flavor == 'win':
       self.WriteVariableList(ninja_file, 'asmflags',
-                             map(self.ExpandSpecial, asmflags))
+                             list(map(self.ExpandSpecial, asmflags)))
       self.WriteVariableList(ninja_file, 'rcflags',
           [QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
            for f in self.msvs_settings.GetRcflags(config_name,
@@ -1013,18 +1013,18 @@ class NinjaWriter(object):
     arflags = config.get('arflags', [])
 
     self.WriteVariableList(ninja_file, 'cflags',
-                           map(self.ExpandSpecial, cflags))
+                           list(map(self.ExpandSpecial, cflags)))
     self.WriteVariableList(ninja_file, 'cflags_c',
-                           map(self.ExpandSpecial, cflags_c))
+                           list(map(self.ExpandSpecial, cflags_c)))
     self.WriteVariableList(ninja_file, 'cflags_cc',
-                           map(self.ExpandSpecial, cflags_cc))
+                           list(map(self.ExpandSpecial, cflags_cc)))
     if self.flavor == 'mac':
       self.WriteVariableList(ninja_file, 'cflags_objc',
-                             map(self.ExpandSpecial, cflags_objc))
+                             list(map(self.ExpandSpecial, cflags_objc)))
       self.WriteVariableList(ninja_file, 'cflags_objcc',
-                             map(self.ExpandSpecial, cflags_objcc))
+                             list(map(self.ExpandSpecial, cflags_objcc)))
     self.WriteVariableList(ninja_file, 'arflags',
-                           map(self.ExpandSpecial, arflags))
+                           list(map(self.ExpandSpecial, arflags)))
     ninja_file.newline()
     outputs = []
     has_rc_source = False
@@ -1233,7 +1233,7 @@ class NinjaWriter(object):
           ldflags.append('-Wl,-rpath=%s' % self.target_rpath)
         ldflags.append('-Wl,-rpath-link=%s' % rpath)
     self.WriteVariableList(ninja_file, 'ldflags',
-                           map(self.ExpandSpecial, ldflags))
+                           list(map(self.ExpandSpecial, ldflags)))
 
     library_dirs = config.get('library_dirs', [])
     if self.flavor == 'win':
@@ -1247,8 +1247,8 @@ class NinjaWriter(object):
                                          self.flavor)
                       for l in library_dirs]
 
-    libraries = gyp.common.uniquer(map(self.ExpandSpecial,
-                                       spec.get('libraries', [])))
+    libraries = gyp.common.uniquer(list(map(self.ExpandSpecial,
+                                       spec.get('libraries', []))))
     if self.flavor == 'mac':
       libraries = self.xcode_settings.AdjustLibraries(libraries, config_name)
     elif self.flavor == 'win':
@@ -1525,7 +1525,7 @@ class NinjaWriter(object):
 
     if type in ('static_library', 'loadable_module', 'shared_library',
                         'executable'):
-      return '%s%s%s' % (prefix, target, extension)
+      return '{}{}{}'.format(prefix, target, extension)
     elif type == 'none':
       return '%s.stamp' % target
     else:
@@ -1943,7 +1943,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
       wrappers[key[:-len('_wrapper')]] = os.path.join(build_to_root, value)
 
   # Support wrappers from environment variables too.
-  for key, value in os.environ.iteritems():
+  for key, value in os.environ.items():
     if key.lower().endswith('_wrapper'):
       key_prefix = key[:-len('_wrapper')]
       key_prefix = re.sub(r'\.HOST$', '.host', key_prefix)
@@ -1963,7 +1963,7 @@ def GenerateOutputForConfig(target_list, target_dicts, data, params,
               configs, generator_flags)
     cl_paths = gyp.msvs_emulation.GenerateEnvironmentFiles(
         toplevel_build, generator_flags, shared_system_includes, OpenOutput)
-    for arch, path in sorted(cl_paths.iteritems()):
+    for arch, path in sorted(cl_paths.items()):
       if clang_cl:
         # If we have selected clang-cl, use that instead.
         path = clang_cl
@@ -2437,7 +2437,7 @@ def PerformBuild(data, configurations, params):
   for config in configurations:
     builddir = os.path.join(options.toplevel_dir, 'out', config)
     arguments = ['ninja', '-C', builddir]
-    print 'Building [%s]: %s' % (config, arguments)
+    print('Building [{}]: {}'.format(config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -2465,7 +2465,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
     GenerateOutputForConfig(target_list, target_dicts, data, params,
                             user_config)
   else:
-    config_names = target_dicts[target_list[0]]['configurations'].keys()
+    config_names = list(target_dicts[target_list[0]]['configurations'].keys())
     if params['parallel']:
       try:
         pool = multiprocessing.Pool(len(config_names))
@@ -2474,7 +2474,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
           arglists.append(
               (target_list, target_dicts, data, params, config_name))
         pool.map(CallGenerateOutputForConfig, arglists)
-      except KeyboardInterrupt, e:
+      except KeyboardInterrupt as e:
         pool.terminate()
         raise e
     else:
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py
index db99d6ab81..6e12b54efb 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/generator/xcode.py
@@ -109,7 +109,7 @@ def CreateXCConfigurationList(configuration_names):
   return xccl
 
 
-class XcodeProject(object):
+class XcodeProject:
   def __init__(self, gyp_path, path, build_file_dict):
     self.gyp_path = gyp_path
     self.path = path
@@ -129,7 +129,7 @@ class XcodeProject(object):
     try:
       os.makedirs(self.path)
       self.created_dir = True
-    except OSError, e:
+    except OSError as e:
       if e.errno != errno.EEXIST:
         raise
 
@@ -183,7 +183,7 @@ class XcodeProject(object):
     # the tree tree view for UI display.
     # Any values set globally are applied to all configurations, then any
     # per-configuration values are applied.
-    for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems():
+    for xck, xcv in self.build_file_dict.get('xcode_settings', {}).items():
       xccl.SetBuildSetting(xck, xcv)
     if 'xcode_config_file' in self.build_file_dict:
       config_ref = self.project.AddOrGetFileInRootGroup(
@@ -196,8 +196,8 @@ class XcodeProject(object):
             build_file_configurations.get(config_name, {})
         if build_file_configuration_named:
           xcc = xccl.ConfigurationNamed(config_name)
-          for xck, xcv in build_file_configuration_named.get('xcode_settings',
-                                                             {}).iteritems():
+          for xck, xcv in (build_file_configuration_named.get('xcode_settings',
+                                                             {})).items():
             xcc.SetBuildSetting(xck, xcv)
           if 'xcode_config_file' in build_file_configuration_named:
             config_ref = self.project.AddOrGetFileInRootGroup(
@@ -273,7 +273,7 @@ class XcodeProject(object):
           script = script + "\n".join(
             ['export %s="%s"' %
              (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val))
-             for (key, val) in command.get('environment').iteritems()]) + "\n"
+             for (key, val) in command.get('environment').items()]) + "\n"
 
         # Some test end up using sockets, files on disk, etc. and can get
         # confused if more then one test runs at a time.  The generator
@@ -454,7 +454,7 @@ sys.exit(subprocess.call(sys.argv[1:]))" """
       same = False
       try:
         same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False)
-      except OSError, e:
+      except OSError as e:
         if e.errno != errno.ENOENT:
           raise
 
@@ -473,10 +473,10 @@ sys.exit(subprocess.call(sys.argv[1:]))" """
         #
         # No way to get the umask without setting a new one?  Set a safe one
         # and then set it back to the old value.
-        umask = os.umask(077)
+        umask = os.umask(0o77)
         os.umask(umask)
 
-        os.chmod(new_pbxproj_path, 0666 & ~umask)
+        os.chmod(new_pbxproj_path, 0o666 & ~umask)
         os.rename(new_pbxproj_path, pbxproj_path)
 
     except Exception:
@@ -566,7 +566,7 @@ def EscapeXcodeDefine(s):
 def PerformBuild(data, configurations, params):
   options = params['options']
 
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -577,7 +577,7 @@ def PerformBuild(data, configurations, params):
   for config in configurations:
     arguments = ['xcodebuild', '-project', xcodeproj_path]
     arguments += ['-configuration', config]
-    print "Building [%s]: %s" % (config, arguments)
+    print("Building [{}]: {}".format(config, arguments))
     subprocess.check_call(arguments)
 
 
@@ -625,7 +625,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
   skip_excluded_files = \
       not generator_flags.get('xcode_list_excluded_files', True)
   xcode_projects = {}
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     (build_file_root, build_file_ext) = os.path.splitext(build_file)
     if build_file_ext != '.gyp':
       continue
@@ -744,7 +744,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
       xctarget_type = gyp.xcodeproj_file.PBXNativeTarget
       try:
         target_properties['productType'] = _types[type_bundle_key]
-      except KeyError, e:
+      except KeyError as e:
         gyp.common.ExceptionAppend(e, "-- unknown product type while "
                                    "writing target %s" % target_name)
         raise
@@ -1011,7 +1011,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
         # TODO(mark): There's a possibilty for collision here.  Consider
         # target "t" rule "A_r" and target "t_A" rule "r".
         makefile_name = '%s.make' % re.sub(
-            '[^a-zA-Z0-9_]', '_' , '%s_%s' % (target_name, rule['rule_name']))
+            '[^a-zA-Z0-9_]', '_' , '{}_{}'.format(target_name, rule['rule_name']))
         makefile_path = os.path.join(xcode_projects[build_file].path,
                                      makefile_name)
         # TODO(mark): try/close?  Write to a temporary file and swap it only
@@ -1024,7 +1024,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
         # target.
         makefile.write('all: \\\n')
         for concrete_output_index in \
-            xrange(0, len(concrete_outputs_by_rule_source)):
+            range(0, len(concrete_outputs_by_rule_source)):
           # Only list the first (index [0]) concrete output of each input
           # in the "all" target.  Otherwise, a parallel make (-j > 1) would
           # attempt to process each input multiple times simultaneously.
@@ -1036,7 +1036,7 @@ def GenerateOutput(target_list, target_dicts, data, params):
             eol = ''
           else:
             eol = ' \\'
-          makefile.write('    %s%s\n' % (concrete_output, eol))
+          makefile.write('    {}{}\n'.format(concrete_output, eol))
 
         for (rule_source, concrete_outputs, message, action) in \
             zip(rule['rule_sources'], concrete_outputs_by_rule_source,
@@ -1047,13 +1047,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
           # rule source.  Collect the names of the directories that are
           # required.
           concrete_output_dirs = []
-          for concrete_output_index in xrange(0, len(concrete_outputs)):
+          for concrete_output_index in range(0, len(concrete_outputs)):
             concrete_output = concrete_outputs[concrete_output_index]
             if concrete_output_index == 0:
               bol = ''
             else:
               bol = '    '
-            makefile.write('%s%s \\\n' % (bol, concrete_output))
+            makefile.write('{}{} \\\n'.format(bol, concrete_output))
 
             concrete_output_dir = posixpath.dirname(concrete_output)
             if (concrete_output_dir and
@@ -1066,13 +1066,13 @@ def GenerateOutput(target_list, target_dicts, data, params):
           # the set of additional rule inputs, if any.
           prerequisites = [rule_source]
           prerequisites.extend(rule.get('inputs', []))
-          for prerequisite_index in xrange(0, len(prerequisites)):
+          for prerequisite_index in range(0, len(prerequisites)):
             prerequisite = prerequisites[prerequisite_index]
             if prerequisite_index == len(prerequisites) - 1:
               eol = ''
             else:
               eol = ' \\'
-            makefile.write('    %s%s\n' % (prerequisite, eol))
+            makefile.write('    {}{}\n'.format(prerequisite, eol))
 
           # Make sure that output directories exist before executing the rule
           # action.
@@ -1288,7 +1288,7 @@ exit 1
           set_define = EscapeXcodeDefine(define)
           xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define)
       if 'xcode_settings' in configuration:
-        for xck, xcv in configuration['xcode_settings'].iteritems():
+        for xck, xcv in configuration['xcode_settings'].items():
           xcbc.SetBuildSetting(xck, xcv)
       if 'xcode_config_file' in configuration:
         config_ref = pbxp.AddOrGetFileInRootGroup(
@@ -1296,7 +1296,7 @@ exit 1
         xcbc.SetBaseConfiguration(config_ref)
 
   build_files = []
-  for build_file, build_file_dict in data.iteritems():
+  for build_file, build_file_dict in data.items():
     if build_file.endswith('.gyp'):
       build_files.append(build_file)
 
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py
index a046a15cc1..d5159a6b83 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/input.py
@@ -2,14 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from compiler.ast import Const
-from compiler.ast import Dict
-from compiler.ast import Discard
-from compiler.ast import List
-from compiler.ast import Module
-from compiler.ast import Node
-from compiler.ast import Stmt
-import compiler
+import ast as _ast_module
 import gyp.common
 import gyp.simple_copy
 import multiprocessing
@@ -183,43 +176,33 @@ def CheckedEval(file_contents):
   Note that this is slower than eval() is.
   """
 
-  ast = compiler.parse(file_contents)
-  assert isinstance(ast, Module)
-  c1 = ast.getChildren()
-  assert c1[0] is None
-  assert isinstance(c1[1], Stmt)
-  c2 = c1[1].getChildren()
-  assert isinstance(c2[0], Discard)
-  c3 = c2[0].getChildren()
-  assert len(c3) == 1
-  return CheckNode(c3[0], [])
+  tree = _ast_module.parse(file_contents, mode='eval')
+  return CheckNode(tree.body, [])
 
 
 def CheckNode(node, keypath):
-  if isinstance(node, Dict):
-    c = node.getChildren()
-    dict = {}
-    for n in range(0, len(c), 2):
-      assert isinstance(c[n], Const)
-      key = c[n].getChildren()[0]
-      if key in dict:
+  if isinstance(node, _ast_module.Dict):
+    d = {}
+    for key_node, val_node in zip(node.keys, node.values):
+      assert isinstance(key_node, _ast_module.Constant)
+      key = key_node.value
+      if key in d:
         raise GypError("Key '" + key + "' repeated at level " +
               repr(len(keypath) + 1) + " with key path '" +
               '.'.join(keypath) + "'")
       kp = list(keypath)  # Make a copy of the list for descending this node.
       kp.append(key)
-      dict[key] = CheckNode(c[n + 1], kp)
-    return dict
-  elif isinstance(node, List):
-    c = node.getChildren()
+      d[key] = CheckNode(val_node, kp)
+    return d
+  elif isinstance(node, _ast_module.List):
     children = []
-    for index, child in enumerate(c):
+    for index, child in enumerate(node.elts):
       kp = list(keypath)  # Copy list.
       kp.append(repr(index))
       children.append(CheckNode(child, kp))
     return children
-  elif isinstance(node, Const):
-    return node.getChildren()[0]
+  elif isinstance(node, _ast_module.Constant):
+    return node.value
   else:
     raise TypeError("Unknown AST node at key path '" + '.'.join(keypath) +
          "': " + repr(node))
@@ -233,7 +216,7 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
   if os.path.exists(build_file_path):
     build_file_contents = open(build_file_path).read()
   else:
-    raise GypError("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
+    raise GypError("{} not found (cwd: {})".format(build_file_path, os.getcwd()))
 
   build_file_data = None
   try:
@@ -242,10 +225,10 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
     else:
       build_file_data = eval(build_file_contents, {'__builtins__': None},
                              None)
-  except SyntaxError, e:
+  except SyntaxError as e:
     e.filename = build_file_path
     raise
-  except Exception, e:
+  except Exception as e:
     gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path)
     raise
 
@@ -265,7 +248,7 @@ def LoadOneBuildFile(build_file_path, data, aux_data, includes,
       else:
         LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
                                       aux_data, None, check)
-    except Exception, e:
+    except Exception as e:
       gyp.common.ExceptionAppend(e,
                                  'while reading includes of ' + build_file_path)
       raise
@@ -302,7 +285,7 @@ def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
                subdict_path, include)
 
   # Recurse into subdictionaries.
-  for k, v in subdict.iteritems():
+  for k, v in subdict.items():
     if type(v) is dict:
       LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data,
                                     None, check)
@@ -467,7 +450,7 @@ def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
       try:
         LoadTargetBuildFile(dependency, data, aux_data, variables,
                             includes, depth, check, load_dependencies)
-      except Exception, e:
+      except Exception as e:
         gyp.common.ExceptionAppend(
           e, 'while loading dependencies of %s' % build_file_path)
         raise
@@ -488,7 +471,7 @@ def CallLoadTargetBuildFile(global_flags,
     signal.signal(signal.SIGINT, signal.SIG_IGN)
 
     # Apply globals so that the worker process behaves the same.
-    for key, value in global_flags.iteritems():
+    for key, value in global_flags.items():
       globals()[key] = value
 
     SetGeneratorGlobals(generator_input_info)
@@ -510,12 +493,12 @@ def CallLoadTargetBuildFile(global_flags,
     return (build_file_path,
             build_file_data,
             dependencies)
-  except GypError, e:
+  except GypError as e:
     sys.stderr.write("gyp: %s\n" % e)
     return None
-  except Exception, e:
-    print >>sys.stderr, 'Exception:', e
-    print >>sys.stderr, traceback.format_exc()
+  except Exception as e:
+    print('Exception:', e, file=sys.stderr)
+    print(traceback.format_exc(), file=sys.stderr)
     return None
 
 
@@ -523,7 +506,7 @@ class ParallelProcessingError(Exception):
   pass
 
 
-class ParallelState(object):
+class ParallelState:
   """Class to keep track of state when processing input files in parallel.
 
   If build files are loaded in parallel, use this to keep track of
@@ -605,7 +588,7 @@ def LoadTargetBuildFilesParallel(build_files, data, variables, includes, depth,
           args = (global_flags, dependency,
                   variables, includes, depth, check, generator_input_info),
           callback = parallel_state.LoadTargetBuildFileCallback)
-  except KeyboardInterrupt, e:
+  except KeyboardInterrupt as e:
     parallel_state.pool.terminate()
     raise e
 
@@ -905,18 +888,22 @@ def ExpandVariables(input, phase, variables, build_file):
                                  stderr=subprocess.PIPE,
                                  stdin=subprocess.PIPE,
                                  cwd=build_file_dir)
-          except Exception, e:
+          except Exception as e:
             raise GypError("%s while executing command '%s' in %s" %
                            (e, contents, build_file))
 
-          p_stdout, p_stderr = p.communicate('')
+          p_stdout, p_stderr = p.communicate(b'')
 
           if p.wait() != 0 or p_stderr:
+            if isinstance(p_stderr, bytes):
+              p_stderr = p_stderr.decode('utf-8', errors='replace')
             sys.stderr.write(p_stderr)
             # Simulate check_call behavior, since check_call only exists
             # in python 2.5 and later.
             raise GypError("Call to '%s' returned exit status %d while in %s." %
                            (contents, p.returncode, build_file))
+          if isinstance(p_stdout, bytes):
+            p_stdout = p_stdout.decode('utf-8', errors='replace')
           replacement = p_stdout.rstrip()
 
         cached_command_results[cache_key] = replacement
@@ -1019,7 +1006,7 @@ def ExpandVariables(input, phase, variables, build_file):
 
   # Convert all strings that are canonically-represented integers into integers.
   if type(output) is list:
-    for index in xrange(0, len(output)):
+    for index in range(0, len(output)):
       if IsStrCanonicalInt(output[index]):
         output[index] = int(output[index])
   elif IsStrCanonicalInt(output):
@@ -1090,13 +1077,13 @@ def EvalSingleCondition(
     if eval(ast_code, {'__builtins__': None}, variables):
       return true_dict
     return false_dict
-  except SyntaxError, e:
+  except SyntaxError as e:
     syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
                                'at character %d.' %
                                (str(e.args[0]), e.text, build_file, e.offset),
                                e.filename, e.lineno, e.offset, e.text)
     raise syntax_error
-  except NameError, e:
+  except NameError as e:
     gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
                                (cond_expr_expanded, build_file))
     raise GypError(e)
@@ -1151,7 +1138,7 @@ def ProcessConditionsInDict(the_dict, phase, variables, build_file):
 def LoadAutomaticVariablesFromDict(variables, the_dict):
   # Any keys with plain string values in the_dict become automatic variables.
   # The variable name is the key name with a "_" character prepended.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     if type(value) in (str, int, list):
       variables['_' + key] = value
 
@@ -1164,7 +1151,7 @@ def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
   # the_dict in the_dict's parent dict.  If the_dict's parent is not a dict
   # (it could be a list or it could be parentless because it is a root dict),
   # the_dict_key will be None.
-  for key, value in the_dict.get('variables', {}).iteritems():
+  for key, value in the_dict.get('variables', {}).items():
     if type(value) not in (str, int, list):
       continue
 
@@ -1173,7 +1160,7 @@ def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
       if variable_name in variables:
         # If the variable is already set, don't set it.
         continue
-      if the_dict_key is 'variables' and variable_name in the_dict:
+      if the_dict_key == 'variables' and variable_name in the_dict:
         # If the variable is set without a % in the_dict, and the_dict is a
         # variables dict (making |variables| a varaibles sub-dict of a
         # variables dict), use the_dict's definition.
@@ -1203,7 +1190,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
     # list before we process them so that you can reference one
     # variable from another.  They will be fully expanded by recursion
     # in ExpandVariables.
-    for key, value in the_dict['variables'].iteritems():
+    for key, value in the_dict['variables'].items():
       variables[key] = value
 
     # Handle the associated variables dict first, so that any variable
@@ -1216,7 +1203,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
 
   LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
 
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     # Skip "variables", which was already processed if present.
     if key != 'variables' and type(value) is str:
       expanded = ExpandVariables(value, phase, variables, build_file)
@@ -1274,7 +1261,7 @@ def ProcessVariablesAndConditionsInDict(the_dict, phase, variables_in,
 
   # Recurse into child dicts, or process child lists which may result in
   # further recursion into descendant dicts.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     # Skip "variables" and string values, which were already processed if
     # present.
     if key == 'variables' or type(value) is str:
@@ -1371,12 +1358,12 @@ def QualifyDependencies(targets):
                              for dep in dependency_sections
                              for op in ('', '!', '/')]
 
-  for target, target_dict in targets.iteritems():
+  for target, target_dict in targets.items():
     target_build_file = gyp.common.BuildFile(target)
     toolset = target_dict['toolset']
     for dependency_key in all_dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
-      for index in xrange(0, len(dependencies)):
+      for index in range(0, len(dependencies)):
         dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
             target_build_file, dependencies[index], toolset)
         if not multiple_toolsets:
@@ -1411,7 +1398,7 @@ def ExpandWildcardDependencies(targets, data):
   dependency list, must be qualified when this function is called.
   """
 
-  for target, target_dict in targets.iteritems():
+  for target, target_dict in targets.items():
     toolset = target_dict['toolset']
     target_build_file = gyp.common.BuildFile(target)
     for dependency_key in dependency_sections:
@@ -1473,7 +1460,7 @@ def Unify(l):
 def RemoveDuplicateDependencies(targets):
   """Makes sure every dependency appears only once in all targets's dependency
   lists."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1489,7 +1476,7 @@ def Filter(l, item):
 def RemoveSelfDependencies(targets):
   """Remove self dependencies from targets that have the prune_self_dependency
   variable set."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1502,7 +1489,7 @@ def RemoveSelfDependencies(targets):
 def RemoveLinkDependenciesFromNoneTargets(targets):
   """Remove dependencies having the 'link_dependency' attribute from the 'none'
   targets."""
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     for dependency_key in dependency_sections:
       dependencies = target_dict.get(dependency_key, [])
       if dependencies:
@@ -1513,7 +1500,7 @@ def RemoveLinkDependenciesFromNoneTargets(targets):
                   Filter(target_dict[dependency_key], t)
 
 
-class DependencyGraphNode(object):
+class DependencyGraphNode:
   """
 
   Attributes:
@@ -1794,14 +1781,14 @@ def BuildDependencyList(targets):
   # Create a DependencyGraphNode for each target.  Put it into a dict for easy
   # access.
   dependency_nodes = {}
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     if target not in dependency_nodes:
       dependency_nodes[target] = DependencyGraphNode(target)
 
   # Set up the dependency links.  Targets that have no dependencies are treated
   # as dependent on root_node.
   root_node = DependencyGraphNode(None)
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     target_node = dependency_nodes[target]
     target_build_file = gyp.common.BuildFile(target)
     dependencies = spec.get('dependencies')
@@ -1825,7 +1812,7 @@ def BuildDependencyList(targets):
     if not root_node.dependents:
       # If all targets have dependencies, add the first target as a dependent
       # of root_node so that the cycle can be discovered from root_node.
-      target = targets.keys()[0]
+      target = list(targets.keys())[0]
       target_node = dependency_nodes[target]
       target_node.dependencies.append(root_node)
       root_node.dependents.append(target_node)
@@ -1844,20 +1831,20 @@ def VerifyNoGYPFileCircularDependencies(targets):
   # Create a DependencyGraphNode for each gyp file containing a target.  Put
   # it into a dict for easy access.
   dependency_nodes = {}
-  for target in targets.iterkeys():
+  for target in targets.keys():
     build_file = gyp.common.BuildFile(target)
     if not build_file in dependency_nodes:
       dependency_nodes[build_file] = DependencyGraphNode(build_file)
 
   # Set up the dependency links.
-  for target, spec in targets.iteritems():
+  for target, spec in targets.items():
     build_file = gyp.common.BuildFile(target)
     build_file_node = dependency_nodes[build_file]
     target_dependencies = spec.get('dependencies', [])
     for dependency in target_dependencies:
       try:
         dependency_build_file = gyp.common.BuildFile(dependency)
-      except GypError, e:
+      except GypError as e:
         gyp.common.ExceptionAppend(
             e, 'while computing dependencies of .gyp file %s' % build_file)
         raise
@@ -1875,7 +1862,7 @@ def VerifyNoGYPFileCircularDependencies(targets):
 
   # Files that have no dependencies are treated as dependent on root_node.
   root_node = DependencyGraphNode(None)
-  for build_file_node in dependency_nodes.itervalues():
+  for build_file_node in dependency_nodes.values():
     if len(build_file_node.dependencies) == 0:
       build_file_node.dependencies.append(root_node)
       root_node.dependents.append(build_file_node)
@@ -1888,7 +1875,7 @@ def VerifyNoGYPFileCircularDependencies(targets):
     if not root_node.dependents:
       # If all files have dependencies, add the first file as a dependent
       # of root_node so that the cycle can be discovered from root_node.
-      file_node = dependency_nodes.values()[0]
+      file_node = list(dependency_nodes.values())[0]
       file_node.dependencies.append(root_node)
       root_node.dependents.append(file_node)
     cycles = []
@@ -2056,7 +2043,7 @@ def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
 
   # Make membership testing of hashables in |to| (in particular, strings)
   # faster.
-  hashable_to_set = set(x for x in to if is_hashable(x))
+  hashable_to_set = {x for x in to if is_hashable(x)}
   for item in fro:
     singleton = False
     if type(item) in (str, int):
@@ -2115,7 +2102,7 @@ def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
 
 def MergeDicts(to, fro, to_file, fro_file):
   # I wanted to name the parameter "from" but it's a Python keyword...
-  for k, v in fro.iteritems():
+  for k, v in fro.items():
     # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
     # copy semantics.  Something else may want to merge from the |fro| dict
     # later, and having the same dict ref pointed to twice in the tree isn't
@@ -2250,13 +2237,13 @@ def SetUpConfigurations(target, target_dict):
   if not 'configurations' in target_dict:
     target_dict['configurations'] = {'Default': {}}
   if not 'default_configuration' in target_dict:
-    concrete = [i for (i, config) in target_dict['configurations'].iteritems()
+    concrete = [i for (i, config) in target_dict['configurations'].items()
                 if not config.get('abstract')]
     target_dict['default_configuration'] = sorted(concrete)[0]
 
   merged_configurations = {}
   configs = target_dict['configurations']
-  for (configuration, old_configuration_dict) in configs.iteritems():
+  for (configuration, old_configuration_dict) in configs.items():
     # Skip abstract configurations (saves work only).
     if old_configuration_dict.get('abstract'):
       continue
@@ -2264,7 +2251,7 @@ def SetUpConfigurations(target, target_dict):
     # Get the inheritance relationship right by making a copy of the target
     # dict.
     new_configuration_dict = {}
-    for (key, target_val) in target_dict.iteritems():
+    for (key, target_val) in target_dict.items():
       key_ext = key[-1:]
       if key_ext in key_suffixes:
         key_base = key[:-1]
@@ -2285,7 +2272,7 @@ def SetUpConfigurations(target, target_dict):
         merged_configurations[configuration])
 
   # Now drop all the abstract ones.
-  for configuration in target_dict['configurations'].keys():
+  for configuration in list(target_dict['configurations'].keys()):
     old_configuration_dict = target_dict['configurations'][configuration]
     if old_configuration_dict.get('abstract'):
       del target_dict['configurations'][configuration]
@@ -2348,7 +2335,7 @@ def ProcessListFiltersInDict(name, the_dict):
 
   lists = []
   del_lists = []
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     operation = key[-1]
     if operation != '!' and operation != '/':
       continue
@@ -2396,7 +2383,7 @@ def ProcessListFiltersInDict(name, the_dict):
     exclude_key = list_key + '!'
     if exclude_key in the_dict:
       for exclude_item in the_dict[exclude_key]:
-        for index in xrange(0, len(the_list)):
+        for index in range(0, len(the_list)):
           if exclude_item == the_list[index]:
             # This item matches the exclude_item, so set its action to 0
             # (exclude).
@@ -2422,7 +2409,7 @@ def ProcessListFiltersInDict(name, the_dict):
           raise ValueError('Unrecognized action ' + action + ' in ' + name + \
                            ' key ' + regex_key)
 
-        for index in xrange(0, len(the_list)):
+        for index in range(0, len(the_list)):
           list_item = the_list[index]
           if list_actions[index] == action_value:
             # Even if the regex matches, nothing will change so continue (regex
@@ -2453,7 +2440,7 @@ def ProcessListFiltersInDict(name, the_dict):
     # the indices of items that haven't been seen yet don't shift.  That means
     # that things need to be prepended to excluded_list to maintain them in the
     # same order that they existed in the_list.
-    for index in xrange(len(list_actions) - 1, -1, -1):
+    for index in range(len(list_actions) - 1, -1, -1):
       if list_actions[index] == 0:
         # Dump anything with action 0 (exclude).  Keep anything with action 1
         # (include) or -1 (no include or exclude seen for the item).
@@ -2466,7 +2453,7 @@ def ProcessListFiltersInDict(name, the_dict):
       the_dict[excluded_key] = excluded_list
 
   # Now recurse into subdicts and lists that may contain dicts.
-  for key, value in the_dict.iteritems():
+  for key, value in the_dict.items():
     if type(value) is dict:
       ProcessListFiltersInDict(key, value)
     elif type(value) is list:
@@ -2523,9 +2510,9 @@ def ValidateSourcesInTarget(target, target_dict, build_file,
     basenames.setdefault(basename, []).append(source)
 
   error = ''
-  for basename, files in basenames.iteritems():
+  for basename, files in basenames.items():
     if len(files) > 1:
-      error += '  %s: %s\n' % (basename, ' '.join(files))
+      error += '  {}: {}\n'.format(basename, ' '.join(files))
 
   if error:
     print('static library %s has several files with the same basename:\n' %
@@ -2662,7 +2649,7 @@ def TurnIntIntoStrInDict(the_dict):
 def TurnIntIntoStrInList(the_list):
   """Given list the_list, recursively converts all integers into strings.
   """
-  for index in xrange(0, len(the_list)):
+  for index in range(0, len(the_list)):
     item = the_list[index]
     if type(item) is int:
       the_list[index] = str(item)
@@ -2780,7 +2767,7 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
       try:
         LoadTargetBuildFile(build_file, data, aux_data,
                             variables, includes, depth, check, True)
-      except Exception, e:
+      except Exception as e:
         gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
         raise
 
@@ -2802,7 +2789,7 @@ def Load(build_files, variables, includes, depth, generator_input_info, check,
   RemoveLinkDependenciesFromNoneTargets(targets)
 
   # Apply exclude (!) and regex (/) list filters only for dependency_sections.
-  for target_name, target_dict in targets.iteritems():
+  for target_name, target_dict in targets.items():
     tmp_dict = {}
     for key_base in dependency_sections:
       for op in ('', '!', '/'):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/input_test.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/input_test.py
index 4234fbb830..1bc5e3d308 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/input_test.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/input_test.py
@@ -22,38 +22,38 @@ class TestFindCycles(unittest.TestCase):
     dependency.dependents.append(dependent)
 
   def test_no_cycle_empty_graph(self):
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_no_cycle_line(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['b'], self.nodes['c'])
     self._create_dependency(self.nodes['c'], self.nodes['d'])
 
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_no_cycle_dag(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['a'], self.nodes['c'])
     self._create_dependency(self.nodes['b'], self.nodes['c'])
 
-    for label, node in self.nodes.iteritems():
-      self.assertEquals([], node.FindCycles())
+    for label, node in self.nodes.items():
+      self.assertEqual([], node.FindCycles())
 
   def test_cycle_self_reference(self):
     self._create_dependency(self.nodes['a'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'], self.nodes['a']]],
+    self.assertEqual([[self.nodes['a'], self.nodes['a']]],
                       self.nodes['a'].FindCycles())
 
   def test_cycle_two_nodes(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
     self._create_dependency(self.nodes['b'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
+    self.assertEqual([[self.nodes['a'], self.nodes['b'], self.nodes['a']]],
                       self.nodes['a'].FindCycles())
-    self.assertEquals([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
+    self.assertEqual([[self.nodes['b'], self.nodes['a'], self.nodes['b']]],
                       self.nodes['b'].FindCycles())
 
   def test_two_cycles(self):
@@ -68,7 +68,7 @@ class TestFindCycles(unittest.TestCase):
        [self.nodes['a'], self.nodes['b'], self.nodes['a']] in cycles)
     self.assertTrue(
        [self.nodes['b'], self.nodes['c'], self.nodes['b']] in cycles)
-    self.assertEquals(2, len(cycles))
+    self.assertEqual(2, len(cycles))
 
   def test_big_cycle(self):
     self._create_dependency(self.nodes['a'], self.nodes['b'])
@@ -77,7 +77,7 @@ class TestFindCycles(unittest.TestCase):
     self._create_dependency(self.nodes['d'], self.nodes['e'])
     self._create_dependency(self.nodes['e'], self.nodes['a'])
 
-    self.assertEquals([[self.nodes['a'],
+    self.assertEqual([[self.nodes['a'],
                         self.nodes['b'],
                         self.nodes['c'],
                         self.nodes['d'],
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py
index 055d79cf22..514e2ec16a 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/mac_tool.py
@@ -30,7 +30,7 @@ def main(args):
     sys.exit(exit_code)
 
 
-class MacTool(object):
+class MacTool:
   """This class performs all the Mac tooling steps. The methods can either be
   executed directly, or dispatched from an argument list."""
 
@@ -163,14 +163,14 @@ class MacTool(object):
   def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
     """Copies the |source| Info.plist to the destination directory |dest|."""
     # Read the source Info.plist into memory.
-    fd = open(source, 'r')
+    fd = open(source)
     lines = fd.read()
     fd.close()
 
     # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
     plist = plistlib.readPlistFromString(lines)
     if keys:
-      plist = dict(plist.items() + json.loads(keys[0]).items())
+      plist = dict(list(plist.items()) + list(json.loads(keys[0]).items()))
     lines = plistlib.writePlistToString(plist)
 
     # Go through all the environment variables and replace them as variables in
@@ -203,7 +203,7 @@ class MacTool(object):
       if lines[i].strip().startswith("<string>${"):
         lines[i] = None
         lines[i - 1] = None
-    lines = '\n'.join(filter(lambda x: x is not None, lines))
+    lines = '\n'.join([x for x in lines if x is not None])
 
     # Write out the file with variables replaced.
     fd = open(dest, 'w')
@@ -237,7 +237,7 @@ class MacTool(object):
 
     dest = os.path.join(os.path.dirname(info_plist), 'PkgInfo')
     fp = open(dest, 'w')
-    fp.write('%s%s' % (package_type, signature_code))
+    fp.write('{}{}'.format(package_type, signature_code))
     fp.close()
 
   def ExecFlock(self, lockfile, *cmd_list):
@@ -266,7 +266,7 @@ class MacTool(object):
     _, err = libtoolout.communicate()
     for line in err.splitlines():
       if not libtool_re.match(line) and not libtool_re5.match(line):
-        print >>sys.stderr, line
+        print(line, file=sys.stderr)
     # Unconditionally touch the output .a file on the command line if present
     # and the command succeeded. A bit hacky.
     if not libtoolout.returncode:
@@ -331,7 +331,7 @@ class MacTool(object):
 
   def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers):
     framework_name = os.path.basename(framework).split('.')[0]
-    all_headers = map(os.path.abspath, all_headers)
+    all_headers = list(map(os.path.abspath, all_headers))
     filelist = {}
     for header in all_headers:
       filename = os.path.basename(header)
@@ -381,7 +381,7 @@ class MacTool(object):
       ])
     if keys:
       keys = json.loads(keys)
-      for key, value in keys.iteritems():
+      for key, value in keys.items():
         arg_name = '--' + key
         if isinstance(value, bool):
           if value:
@@ -395,7 +395,7 @@ class MacTool(object):
           command_line.append(str(value))
     # Note: actool crashes if inputs path are relative, so use os.path.abspath
     # to get absolute path name for inputs.
-    command_line.extend(map(os.path.abspath, inputs))
+    command_line.extend(list(map(os.path.abspath, inputs)))
     subprocess.check_call(command_line)
 
   def ExecMergeInfoPlist(self, output, *inputs):
@@ -476,8 +476,8 @@ class MacTool(object):
     profiles_dir = os.path.join(
         os.environ['HOME'], 'Library', 'MobileDevice', 'Provisioning Profiles')
     if not os.path.isdir(profiles_dir):
-      print >>sys.stderr, (
-          'cannot find mobile provisioning for %s' % bundle_identifier)
+      print((
+          'cannot find mobile provisioning for %s' % bundle_identifier), file=sys.stderr)
       sys.exit(1)
     provisioning_profiles = None
     if profile:
@@ -493,13 +493,13 @@ class MacTool(object):
       app_id_pattern = profile_data.get(
           'Entitlements', {}).get('application-identifier', '')
       for team_identifier in profile_data.get('TeamIdentifier', []):
-        app_id = '%s.%s' % (team_identifier, bundle_identifier)
+        app_id = '{}.{}'.format(team_identifier, bundle_identifier)
         if fnmatch.fnmatch(app_id, app_id_pattern):
           valid_provisioning_profiles[app_id_pattern] = (
               profile_path, profile_data, team_identifier)
     if not valid_provisioning_profiles:
-      print >>sys.stderr, (
-          'cannot find mobile provisioning for %s' % bundle_identifier)
+      print((
+          'cannot find mobile provisioning for %s' % bundle_identifier), file=sys.stderr)
       sys.exit(1)
     # If the user has multiple provisioning profiles installed that can be
     # used for ${bundle_identifier}, pick the most specific one (ie. the
@@ -523,7 +523,7 @@ class MacTool(object):
 
   def _MergePlist(self, merged_plist, plist):
     """Merge |plist| into |merged_plist|."""
-    for key, value in plist.iteritems():
+    for key, value in plist.items():
       if isinstance(value, dict):
         merged_value = merged_plist.get(key, {})
         if isinstance(merged_value, dict):
@@ -633,7 +633,7 @@ class MacTool(object):
       the key was not found.
     """
     if isinstance(data, str):
-      for key, value in substitutions.iteritems():
+      for key, value in substitutions.items():
         data = data.replace('$(%s)' % key, value)
       return data
     if isinstance(data, list):
@@ -663,7 +663,7 @@ def WriteHmap(output_name, filelist):
   count = len(filelist)
   capacity = NextGreaterPowerOf2(count)
   strings_offset = 24 + (12 * capacity)
-  max_value_length = len(max(filelist.items(), key=lambda (k,v):len(v))[1])
+  max_value_length = len(max(list(filelist.items()), key=lambda k_v:len(k_v[1]))[1])
 
   out = open(output_name, "wb")
   out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py
index e4a85a96e6..9f4b7996ec 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/msvs_emulation.py
@@ -94,9 +94,9 @@ def _DoRemapping(element, map):
     if not callable(map):
       map = map.get # Assume it's a dict, otherwise a callable to do the remap.
     if isinstance(element, list) or isinstance(element, tuple):
-      element = filter(None, [map(elem) for elem in element])
+      element = [_f for _f in [list(map(elem)) for elem in element] if _f]
     else:
-      element = map(element)
+      element = list(map(element))
   return element
 
 
@@ -183,7 +183,7 @@ def ExtractSharedMSVSSystemIncludes(configs, generator_flags):
   return expanded_system_includes
 
 
-class MsvsSettings(object):
+class MsvsSettings:
   """A class that understands the gyp 'msvs_...' values (especially the
   msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
   class helps map those settings to command line options."""
@@ -205,7 +205,7 @@ class MsvsSettings(object):
     configs = spec['configurations']
     for field, default in supported_fields:
       setattr(self, field, {})
-      for configname, config in configs.iteritems():
+      for configname, config in configs.items():
         getattr(self, field)[configname] = config.get(field, default())
 
     self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
@@ -281,7 +281,7 @@ class MsvsSettings(object):
     result = _AddPrefix(result, prefix)
     return _AppendOrReturn(append, result)
 
-  class _GetWrapper(object):
+  class _GetWrapper:
     def __init__(self, parent, field, base_path, append=None):
       self.parent = parent
       self.field = field
@@ -472,7 +472,7 @@ class MsvsSettings(object):
       # New flag required in 2013 to maintain previous PDB behavior.
       cflags.append('/FS')
     # ninja handles parallelism by itself, don't have the compiler do it too.
-    cflags = filter(lambda x: not x.startswith('/MP'), cflags)
+    cflags = [x for x in cflags if not x.startswith('/MP')]
     return cflags
 
   def _GetPchFlags(self, config, extension):
@@ -602,7 +602,7 @@ class MsvsSettings(object):
           ('VCLinkerTool', 'StackCommitSize'), config, default='')
       if stack_commit_size:
         stack_commit_size = ',' + stack_commit_size
-      ldflags.append('/STACK:%s%s' % (stack_reserve_size, stack_commit_size))
+      ldflags.append('/STACK:{}{}'.format(stack_reserve_size, stack_commit_size))
 
     ld('TerminalServerAware', map={'1': ':NO', '2': ''}, prefix='/TSAWARE')
     ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
@@ -638,8 +638,7 @@ class MsvsSettings(object):
 
     # If the base address is not specifically controlled, DYNAMICBASE should
     # be on by default.
-    base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
-                        ldflags)
+    base_flags = [x for x in ldflags if 'DYNAMICBASE' in x or x == '/FIXED']
     if not base_flags:
       ldflags.append('/DYNAMICBASE')
 
@@ -647,10 +646,10 @@ class MsvsSettings(object):
     # documentation that says this only defaults to on when the subsystem is
     # Vista or greater (which applies to the linker), the IDE defaults it on
     # unless it's explicitly off.
-    if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
+    if not [x for x in ldflags if 'NXCOMPAT' in x]:
       ldflags.append('/NXCOMPAT')
 
-    have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
+    have_def_file = [x for x in ldflags if x.startswith('/DEF:')]
     manifest_flags, intermediate_manifest, manifest_files = \
         self._GetLdManifestFlags(config, manifest_base_name, gyp_to_build_path,
                                  is_executable and not have_def_file, build_dir)
@@ -716,10 +715,10 @@ class MsvsSettings(object):
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
   <security>
     <requestedPrivileges>
-      <requestedExecutionLevel level='%s' uiAccess='%s' />
+      <requestedExecutionLevel level='{}' uiAccess='{}' />
     </requestedPrivileges>
   </security>
-</trustInfo>''' % (execution_level_map[execution_level], ui_access)
+</trustInfo>'''.format(execution_level_map[execution_level], ui_access)
     else:
       inner = ''
 
@@ -806,7 +805,7 @@ class MsvsSettings(object):
     bash_cmd = ' '.join(args)
     cmd = (
         'call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
-        'bash -c "%s ; %s"' % (cd, bash_cmd))
+        'bash -c "{} ; {}"'.format(cd, bash_cmd))
     return cmd
 
   def IsRuleRunUnderCygwin(self, rule):
@@ -873,7 +872,7 @@ def _LanguageMatchesForPch(source_ext, pch_source_ext):
           (source_ext in cc_exts and pch_source_ext in cc_exts))
 
 
-class PrecompiledHeader(object):
+class PrecompiledHeader:
   """Helper to generate dependencies and build rules to handle generation of
   precompiled headers. Interface matches the GCH handler in xcode_emulation.py.
   """
@@ -917,10 +916,10 @@ class PrecompiledHeader(object):
     if input == self.pch_source:
       pch_output = ['/Yc' + self._PchHeader()]
       if command == 'cxx':
-        return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
+        return ([('cflags_cc', list(map(expand_special, cflags_cc + pch_output)))],
                 self.output_obj, [])
       elif command == 'cc':
-        return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
+        return ([('cflags_c', list(map(expand_special, cflags_c + pch_output)))],
                 self.output_obj, [])
     return [], output, implicit
 
@@ -942,7 +941,7 @@ def ExpandMacros(string, expansions):
   """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
   for the canonical way to retrieve a suitable dict."""
   if '$' in string:
-    for old, new in expansions.iteritems():
+    for old, new in expansions.items():
       assert '$(' not in new, new
       string = string.replace(old, new)
   return string
@@ -990,7 +989,7 @@ def _FormatAsEnvironmentBlock(envvar_dict):
   CreateProcess documentation for more details."""
   block = ''
   nul = '\0'
-  for key, value in envvar_dict.iteritems():
+  for key, value in envvar_dict.items():
     block += key + '=' + value + nul
   block += nul
   return block
@@ -1065,9 +1064,9 @@ def VerifyMissingSources(sources, build_dir, generator_flags, gyp_to_ninja):
   VS, and we want this check to match for people/bots that build using ninja,
   so they're not surprised when the VS build fails."""
   if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
-    no_specials = filter(lambda x: '$' not in x, sources)
+    no_specials = [x for x in sources if '$' not in x]
     relative = [os.path.join(build_dir, gyp_to_ninja(s)) for s in no_specials]
-    missing = filter(lambda x: not os.path.exists(x), relative)
+    missing = [x for x in relative if not os.path.exists(x)]
     if missing:
       # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
       # path for a slightly less crazy looking output.
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py
index d2948f06c0..e260398af8 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/ninja_syntax.py
@@ -15,7 +15,7 @@ import re
 def escape_path(word):
     return word.replace('$ ','$$ ').replace(' ','$ ').replace(':', '$:')
 
-class Writer(object):
+class Writer:
     def __init__(self, output, width=78):
         self.output = output
         self.width = width
@@ -31,8 +31,8 @@ class Writer(object):
         if value is None:
             return
         if isinstance(value, list):
-            value = ' '.join(filter(None, value))  # Filter out empty strings.
-        self._line('%s = %s' % (key, value), indent)
+            value = ' '.join([_f for _f in value if _f])  # Filter out empty strings.
+        self._line('{} = {}'.format(key, value), indent)
 
     def pool(self, name, depth):
         self._line('pool %s' % name)
@@ -68,15 +68,15 @@ class Writer(object):
         all_inputs = list(map(escape_path, all_inputs))
 
         if implicit:
-            implicit = map(escape_path, self._as_list(implicit))
+            implicit = list(map(escape_path, self._as_list(implicit)))
             all_inputs.append('|')
             all_inputs.extend(implicit)
         if order_only:
-            order_only = map(escape_path, self._as_list(order_only))
+            order_only = list(map(escape_path, self._as_list(order_only)))
             all_inputs.append('||')
             all_inputs.extend(order_only)
 
-        self._line('build %s: %s' % (' '.join(out_outputs),
+        self._line('build {}: {}'.format(' '.join(out_outputs),
                                         ' '.join([rule] + all_inputs)))
 
         if variables:
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/ordered_dict.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/ordered_dict.py
index a1e89f9199..a1be68ec57 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/ordered_dict.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/ordered_dict.py
@@ -30,9 +30,9 @@
 # Passes Python2.7's test suite and incorporates all the latest updates.
 
 try:
-    from thread import get_ident as _get_ident
+    from _thread import get_ident as _get_ident
 except ImportError:
-    from dummy_thread import get_ident as _get_ident
+    from _thread import get_ident as _get_ident
 
 try:
     from _abcoll import KeysView, ValuesView, ItemsView
@@ -106,7 +106,7 @@ class OrderedDict(dict):
     def clear(self):
         'od.clear() -> None.  Remove all items from od.'
         try:
-            for node in self.__map.itervalues():
+            for node in self.__map.values():
                 del node[:]
             root = self.__root
             root[:] = [root, root, None]
@@ -231,8 +231,8 @@ class OrderedDict(dict):
         _repr_running[call_key] = 1
         try:
             if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
+                return '{}()'.format(self.__class__.__name__)
+            return '{}({!r})'.format(self.__class__.__name__, list(self.items()))
         finally:
             del _repr_running[call_key]
 
@@ -267,7 +267,7 @@ class OrderedDict(dict):
 
         '''
         if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
+            return len(self)==len(other) and list(self.items()) == list(other.items())
         return dict.__eq__(self, other)
 
     def __ne__(self, other):
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/simple_copy.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/simple_copy.py
index 74c98c5a79..571baa4193 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/simple_copy.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/simple_copy.py
@@ -28,8 +28,8 @@ _deepcopy_dispatch = d = {}
 def _deepcopy_atomic(x):
   return x
 
-for x in (type(None), int, long, float,
-          bool, str, unicode, type):
+for x in (type(None), int, int, float,
+          bool, str, str, type):
   d[x] = _deepcopy_atomic
 
 def _deepcopy_list(x):
@@ -38,7 +38,7 @@ d[list] = _deepcopy_list
 
 def _deepcopy_dict(x):
   y = {}
-  for key, value in x.iteritems():
+  for key, value in x.items():
     y[deepcopy(key)] = deepcopy(value)
   return y
 d[dict] = _deepcopy_dict
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py
index 1c843a0b6c..a5fb64e86a 100755
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/win_tool.py
@@ -30,7 +30,7 @@ def main(args):
     sys.exit(exit_code)
 
 
-class WinTool(object):
+class WinTool:
   """This class performs all the Windows tooling steps. The methods can either
   be executed directly, or dispatched from an argument list."""
 
@@ -134,7 +134,7 @@ class WinTool(object):
       if (not line.startswith('   Creating library ') and
           not line.startswith('Generating code') and
           not line.startswith('Finished generating code')):
-        print line
+        print(line)
     return link.returncode
 
   def ExecLinkWithManifests(self, arch, embed_manifest, out, ldcmd, resname,
@@ -223,7 +223,7 @@ class WinTool(object):
     out, _ = popen.communicate()
     for line in out.splitlines():
       if line and 'manifest authoring warning 81010002' not in line:
-        print line
+        print(line)
     return popen.returncode
 
   def ExecManifestToRc(self, arch, *args):
@@ -232,7 +232,7 @@ class WinTool(object):
     and resource name which can be "1" (for executables) or "2" (for DLLs)."""
     manifest_path, resource_path, resource_name = args
     with open(resource_path, 'wb') as output:
-      output.write('#include <windows.h>\n%s RT_MANIFEST "%s"' % (
+      output.write('#include <windows.h>\n{} RT_MANIFEST "{}"'.format(
         resource_name,
         os.path.abspath(manifest_path).replace('\\', '/')))
 
@@ -259,11 +259,11 @@ class WinTool(object):
     # objidl.idl
     lines = out.splitlines()
     prefixes = ('Processing ', '64 bit Processing ')
-    processing = set(os.path.basename(x)
-                     for x in lines if x.startswith(prefixes))
+    processing = {os.path.basename(x)
+                     for x in lines if x.startswith(prefixes)}
     for line in lines:
       if not line.startswith(prefixes) and line not in processing:
-        print line
+        print(line)
     return popen.returncode
 
   def ExecAsmWrapper(self, arch, *args):
@@ -277,7 +277,7 @@ class WinTool(object):
           not line.startswith('Microsoft (R) Macro Assembler') and
           not line.startswith(' Assembling: ') and
           line):
-        print line
+        print(line)
     return popen.returncode
 
   def ExecRcWrapper(self, arch, *args):
@@ -291,7 +291,7 @@ class WinTool(object):
       if (not line.startswith('Microsoft (R) Windows (R) Resource Compiler') and
           not line.startswith('Copyright (C) Microsoft Corporation') and
           line):
-        print line
+        print(line)
     return popen.returncode
 
   def ExecActionWrapper(self, arch, rspfile, *dir):
@@ -300,7 +300,7 @@ class WinTool(object):
     env = self._GetEnv(arch)
     # TODO(scottmg): This is a temporary hack to get some specific variables
     # through to actions that are set after gyp-time. http://crbug.com/333738.
-    for k, v in os.environ.iteritems():
+    for k, v in os.environ.items():
       if k not in env:
         env[k] = v
     args = open(rspfile).read()
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py
index dba8e7699e..b99d5eac27 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_emulation.py
@@ -36,7 +36,7 @@ def XcodeArchsVariableMapping(archs, archs_including_64_bit=None):
     mapping['$(ARCHS_STANDARD_INCLUDING_64_BIT)'] = archs_including_64_bit
   return mapping
 
-class XcodeArchsDefault(object):
+class XcodeArchsDefault:
   """A class to resolve ARCHS variable from xcode_settings, resolving Xcode
   macros and implementing filtering by VALID_ARCHS. The expansion of macros
   depends on the SDKROOT used ("macosx", "iphoneos", "iphonesimulator") and
@@ -73,7 +73,7 @@ class XcodeArchsDefault(object):
             if arch not in expanded_archs:
               expanded_archs.append(arch)
         except KeyError as e:
-          print 'Warning: Ignoring unsupported variable "%s".' % variable
+          print('Warning: Ignoring unsupported variable "%s".' % variable)
       elif arch not in expanded_archs:
         expanded_archs.append(arch)
     return expanded_archs
@@ -141,7 +141,7 @@ def GetXcodeArchsDefault():
   return XCODE_ARCHS_DEFAULT_CACHE
 
 
-class XcodeSettings(object):
+class XcodeSettings:
   """A class that understands the gyp 'xcode_settings' object."""
 
   # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
@@ -171,7 +171,7 @@ class XcodeSettings(object):
     # the same for all configs are implicitly per-target settings.
     self.xcode_settings = {}
     configs = spec['configurations']
-    for configname, config in configs.iteritems():
+    for configname, config in configs.items():
       self.xcode_settings[configname] = config.get('xcode_settings', {})
       self._ConvertConditionalKeys(configname)
       if self.xcode_settings[configname].get('IPHONEOS_DEPLOYMENT_TARGET',
@@ -197,8 +197,8 @@ class XcodeSettings(object):
           new_key = key.split("[")[0]
           settings[new_key] = settings[key]
       else:
-        print 'Warning: Conditional keys not implemented, ignoring:', \
-              ' '.join(conditional_keys)
+        print('Warning: Conditional keys not implemented, ignoring:', \
+              ' '.join(conditional_keys))
       del settings[key]
 
   def _Settings(self):
@@ -216,7 +216,7 @@ class XcodeSettings(object):
 
   def _WarnUnimplemented(self, test_key):
     if test_key in self._Settings():
-      print 'Warning: Ignoring not yet implemented key "%s".' % test_key
+      print('Warning: Ignoring not yet implemented key "%s".' % test_key)
 
   def IsBinaryOutputFormat(self, configname):
     default = "binary" if self.isIOS else "xml"
@@ -271,7 +271,7 @@ class XcodeSettings(object):
       else:
         return '.' + self.spec.get('product_extension', 'app')
     else:
-      assert False, "Don't know extension for '%s', target '%s'" % (
+      assert False, "Don't know extension for '{}', target '{}'".format(
           self.spec['type'], self.spec['target_name'])
 
   def GetProductName(self):
@@ -963,7 +963,7 @@ class XcodeSettings(object):
         result = dict(self.xcode_settings[configname])
         first_pass = False
       else:
-        for key, value in self.xcode_settings[configname].iteritems():
+        for key, value in self.xcode_settings[configname].items():
           if key not in result:
             continue
           elif result[key] != value:
@@ -1023,7 +1023,7 @@ class XcodeSettings(object):
 
       if not quiet:
         result.append('echo STRIP\\(%s\\)' % self.spec['target_name'])
-      result.append('strip %s %s' % (strip_flags, output_binary))
+      result.append('strip {} {}'.format(strip_flags, output_binary))
 
     self.configname = None
     return result
@@ -1042,7 +1042,7 @@ class XcodeSettings(object):
         self.spec['type'] != 'static_library'):
       if not quiet:
         result.append('echo DSYMUTIL\\(%s\\)' % self.spec['target_name'])
-      result.append('dsymutil %s -o %s' % (output_binary, output + '.dSYM'))
+      result.append('dsymutil {} -o {}'.format(output_binary, output + '.dSYM'))
 
     self.configname = None
     return result
@@ -1074,7 +1074,7 @@ class XcodeSettings(object):
       source = os.path.join("${BUILT_PRODUCTS_DIR}", product_name)
       test_host = os.path.dirname(settings.get('TEST_HOST'));
       xctest_destination = os.path.join(test_host, 'PlugIns', product_name)
-      postbuilds.extend(['ditto %s %s' % (source, xctest_destination)])
+      postbuilds.extend(['ditto {} {}'.format(source, xctest_destination)])
 
     key = self._GetIOSCodeSignIdentityKey(settings)
     if not key:
@@ -1084,8 +1084,8 @@ class XcodeSettings(object):
     unimpl = ['OTHER_CODE_SIGN_FLAGS']
     unimpl = set(unimpl) & set(self.xcode_settings[configname].keys())
     if unimpl:
-      print 'Warning: Some codesign keys not implemented, ignoring: %s' % (
-          ', '.join(sorted(unimpl)))
+      print('Warning: Some codesign keys not implemented, ignoring: %s' % (
+          ', '.join(sorted(unimpl))))
 
     if self._IsXCTest():
       # For device xctests, Xcode copies two extra frameworks into $TEST_HOST.
@@ -1098,10 +1098,10 @@ class XcodeSettings(object):
       for framework in frameworks:
         source = os.path.join(platform_root, framework)
         destination = os.path.join(frameworks_dir, os.path.basename(framework))
-        postbuilds.extend(['ditto %s %s' % (source, destination)])
+        postbuilds.extend(['ditto {} {}'.format(source, destination)])
 
         # Then re-sign everything with 'preserve=True'
-        postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+        postbuilds.extend(['{} code-sign-bundle "{}" "{}" "{}" "{}" {}'.format(
             os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
             settings.get('CODE_SIGN_ENTITLEMENTS', ''),
             settings.get('PROVISIONING_PROFILE', ''), destination, True)
@@ -1109,13 +1109,13 @@ class XcodeSettings(object):
       plugin_dir = os.path.join(test_host, 'PlugIns')
       targets = [os.path.join(plugin_dir, product_name), test_host]
       for target in targets:
-        postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+        postbuilds.extend(['{} code-sign-bundle "{}" "{}" "{}" "{}" {}'.format(
             os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
             settings.get('CODE_SIGN_ENTITLEMENTS', ''),
             settings.get('PROVISIONING_PROFILE', ''), target, True)
         ])
 
-    postbuilds.extend(['%s code-sign-bundle "%s" "%s" "%s" "%s" %s' % (
+    postbuilds.extend(['{} code-sign-bundle "{}" "{}" "{}" "{}" {}'.format(
         os.path.join('${TARGET_BUILD_DIR}', 'gyp-mac-tool'), key,
         settings.get('CODE_SIGN_ENTITLEMENTS', ''),
         settings.get('PROVISIONING_PROFILE', ''),
@@ -1272,7 +1272,7 @@ class XcodeSettings(object):
     return ''
 
 
-class MacPrefixHeader(object):
+class MacPrefixHeader:
   """A class that helps with emulating Xcode's GCC_PREFIX_HEADER feature.
 
   This feature consists of several pieces:
@@ -1725,7 +1725,7 @@ def _TopologicallySortedEnvVarKeys(env):
     # definition contains all variables it references in a single string.
     # We can then reverse the result of the topological sort at the end.
     # Since: reverse(topsort(DAG)) = topsort(reverse_edges(DAG))
-    matches = set([v for v in regex.findall(env[node]) if v in env])
+    matches = {v for v in regex.findall(env[node]) if v in env}
     for dependee in matches:
       assert '${' not in dependee, 'Nested variables not supported: ' + dependee
     return matches
@@ -1734,10 +1734,10 @@ def _TopologicallySortedEnvVarKeys(env):
     # Topologically sort, and then reverse, because we used an edge definition
     # that's inverted from the expected result of this function (see comment
     # above).
-    order = gyp.common.TopologicallySorted(env.keys(), GetEdges)
+    order = gyp.common.TopologicallySorted(list(env.keys()), GetEdges)
     order.reverse()
     return order
-  except gyp.common.CycleError, e:
+  except gyp.common.CycleError as e:
     raise GypError(
         'Xcode environment variables are cyclically dependent: ' + str(e.nodes))
 
@@ -1755,7 +1755,7 @@ def GetSpecPostbuildCommands(spec, quiet=False):
   postbuilds = []
   for postbuild in spec.get('postbuilds', []):
     if not quiet:
-      postbuilds.append('echo POSTBUILD\\(%s\\) %s' % (
+      postbuilds.append('echo POSTBUILD\\({}\\) {}'.format(
             spec['target_name'], postbuild['postbuild_name']))
     postbuilds.append(gyp.common.EncodePOSIXShellList(postbuild['action']))
   return postbuilds
@@ -1774,10 +1774,10 @@ def _HasIOSTarget(targets):
 def _AddIOSDeviceConfigurations(targets):
   """Clone all targets and append -iphoneos to the name. Configure these targets
   to build for iOS devices and use correct architectures for those builds."""
-  for target_dict in targets.itervalues():
+  for target_dict in targets.values():
     toolset = target_dict['toolset']
     configs = target_dict['configurations']
-    for config_name, simulator_config_dict in dict(configs).iteritems():
+    for config_name, simulator_config_dict in dict(configs).items():
       iphoneos_config_dict = copy.deepcopy(simulator_config_dict)
       configs[config_name + '-iphoneos'] = iphoneos_config_dict
       configs[config_name + '-iphonesimulator'] = simulator_config_dict
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_ninja.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_ninja.py
index bc76ffff4e..6614247cea 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_ninja.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcode_ninja.py
@@ -28,7 +28,7 @@ def _WriteWorkspace(main_gyp, sources_gyp, params):
     workspace_path = os.path.join(options.generator_output, workspace_path)
   try:
     os.makedirs(workspace_path)
-  except OSError, e:
+  except OSError as e:
     if e.errno != errno.EEXIST:
       raise
   output_string = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
@@ -42,11 +42,11 @@ def _WriteWorkspace(main_gyp, sources_gyp, params):
   workspace_file = os.path.join(workspace_path, "contents.xcworkspacedata")
 
   try:
-    with open(workspace_file, 'r') as input_file:
+    with open(workspace_file) as input_file:
       input_string = input_file.read()
       if input_string == output_string:
         return
-  except IOError:
+  except OSError:
     # Ignore errors if the file doesn't exist.
     pass
 
@@ -85,7 +85,7 @@ def _TargetFromSpec(old_spec, params):
         "%s/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)" % ninja_toplevel
 
   if 'configurations' in old_spec:
-    for config in old_spec['configurations'].iterkeys():
+    for config in old_spec['configurations'].keys():
       old_xcode_settings = \
         old_spec['configurations'][config].get('xcode_settings', {})
       if 'IPHONEOS_DEPLOYMENT_TARGET' in old_xcode_settings:
@@ -167,7 +167,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
     params: Dict of global options for gyp.
   """
   orig_gyp = params['build_files'][0]
-  for gyp_name, gyp_dict in data.iteritems():
+  for gyp_name, gyp_dict in data.items():
     if gyp_name == orig_gyp:
       depth = gyp_dict['_DEPTH']
 
@@ -206,7 +206,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
     if IsValidTargetForWrapper(target_extras, executable_target_pattern, spec):
       # Add to new_target_list.
       target_name = spec.get('target_name')
-      new_target_name = '%s:%s#target' % (main_gyp, target_name)
+      new_target_name = '{}:{}#target'.format(main_gyp, target_name)
       new_target_list.append(new_target_name)
 
       # Add to new_target_dicts.
@@ -238,7 +238,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
       not generator_flags.get('xcode_ninja_list_excluded_files', True)
 
   sources = []
-  for target, target_dict in target_dicts.iteritems():
+  for target, target_dict in target_dicts.items():
     base = os.path.dirname(target)
     files = target_dict.get('sources', []) + \
             target_dict.get('mac_bundle_resources', [])
@@ -268,7 +268,7 @@ def CreateWrapper(target_list, target_dicts, data, params):
   sources_gyp = \
       os.path.join(os.path.dirname(main_gyp), sources_target_name + ".gyp")
   fully_qualified_target_name = \
-      '%s:%s#target' % (sources_gyp, sources_target_name)
+      '{}:{}#target'.format(sources_gyp, sources_target_name)
 
   # Add to new_target_list, new_target_dicts and new_data.
   new_target_list.append(fully_qualified_target_name)
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py
index e69235f724..e2235bc5db 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xcodeproj_file.py
@@ -198,7 +198,7 @@ def SourceTreeAndPathFromPath(input_path):
 def ConvertVariablesToShellSyntax(input_string):
   return re.sub(r'\$\((.*?)\)', '${\\1}', input_string)
 
-class XCObject(object):
+class XCObject:
   """The abstract base of all class types used in Xcode project files.
 
   Class variables:
@@ -300,8 +300,8 @@ class XCObject(object):
     try:
       name = self.Name()
     except NotImplementedError:
-      return '<%s at 0x%x>' % (self.__class__.__name__, id(self))
-    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+      return '<{} at 0x{:x}>'.format(self.__class__.__name__, id(self))
+    return '<{} {!r} at 0x{:x}>'.format(self.__class__.__name__, name, id(self))
 
   def Copy(self):
     """Make a copy of this object.
@@ -314,7 +314,7 @@ class XCObject(object):
     """
 
     that = self.__class__(id=self.id, parent=self.parent)
-    for key, value in self._properties.iteritems():
+    for key, value in self._properties.items():
       is_strong = self._schema[key][2]
 
       if isinstance(value, XCObject):
@@ -324,7 +324,7 @@ class XCObject(object):
           that._properties[key] = new_value
         else:
           that._properties[key] = value
-      elif isinstance(value, str) or isinstance(value, unicode) or \
+      elif isinstance(value, str) or isinstance(value, str) or \
            isinstance(value, int):
         that._properties[key] = value
       elif isinstance(value, list):
@@ -452,7 +452,7 @@ class XCObject(object):
       digest_int_count = hash.digest_size / 4
       digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest())
       id_ints = [0, 0, 0]
-      for index in xrange(0, digest_int_count):
+      for index in range(0, digest_int_count):
         id_ints[index % 3] ^= digest_ints[index]
       self.id = '%08X%08X%08X' % tuple(id_ints)
 
@@ -475,7 +475,7 @@ class XCObject(object):
     """Returns a list of all of this object's owned (strong) children."""
 
     children = []
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong) = attributes[0:3]
       if is_strong and property in self._properties:
         if not is_list:
@@ -603,7 +603,7 @@ class XCObject(object):
       comment = value.Comment()
     elif isinstance(value, str):
       printable += self._EncodeString(value)
-    elif isinstance(value, unicode):
+    elif isinstance(value, str):
       printable += self._EncodeString(value.encode('utf-8'))
     elif isinstance(value, int):
       printable += str(value)
@@ -622,7 +622,7 @@ class XCObject(object):
         printable += end_tabs + ')'
     elif isinstance(value, dict):
       printable = '{' + sep
-      for item_key, item_value in sorted(value.iteritems()):
+      for item_key, item_value in sorted(value.items()):
         printable += element_tabs + \
             self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \
             self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \
@@ -691,7 +691,7 @@ class XCObject(object):
           printable_value[0] == '"' and printable_value[-1] == '"':
         printable_value = printable_value[1:-1]
       printable += printable_key + ' = ' + printable_value + ';' + after_kv
-    except TypeError, e:
+    except TypeError as e:
       gyp.common.ExceptionAppend(e,
                                  'while printing key "%s"' % key)
       raise
@@ -730,7 +730,7 @@ class XCObject(object):
     self._XCKVPrint(file, 3, 'isa', self.__class__.__name__)
 
     # The remaining elements of an object dictionary are sorted alphabetically.
-    for property, value in sorted(self._properties.iteritems()):
+    for property, value in sorted(self._properties.items()):
       self._XCKVPrint(file, 3, property, value)
 
     # End the object.
@@ -752,7 +752,7 @@ class XCObject(object):
     if properties is None:
       return
 
-    for property, value in properties.iteritems():
+    for property, value in properties.items():
       # Make sure the property is in the schema.
       if not property in self._schema:
         raise KeyError(property + ' not in ' + self.__class__.__name__)
@@ -766,7 +766,7 @@ class XCObject(object):
                 ' must be list, not ' + value.__class__.__name__)
         for item in value:
           if not isinstance(item, property_type) and \
-             not (item.__class__ == unicode and property_type == str):
+             not (item.__class__ == str and property_type == str):
             # Accept unicode where str is specified.  str is treated as
             # UTF-8-encoded.
             raise TypeError(
@@ -774,7 +774,7 @@ class XCObject(object):
                   ' must be ' + property_type.__name__ + ', not ' + \
                   item.__class__.__name__)
       elif not isinstance(value, property_type) and \
-           not (value.__class__ == unicode and property_type == str):
+           not (value.__class__ == str and property_type == str):
         # Accept unicode where str is specified.  str is treated as
         # UTF-8-encoded.
         raise TypeError(
@@ -788,7 +788,7 @@ class XCObject(object):
             self._properties[property] = value.Copy()
           else:
             self._properties[property] = value
-        elif isinstance(value, str) or isinstance(value, unicode) or \
+        elif isinstance(value, str) or isinstance(value, str) or \
              isinstance(value, int):
           self._properties[property] = value
         elif isinstance(value, list):
@@ -865,7 +865,7 @@ class XCObject(object):
 
     # TODO(mark): A stronger verification mechanism is needed.  Some
     # subclasses need to perform validation beyond what the schema can enforce.
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong, is_required) = attributes[0:4]
       if is_required and not property in self._properties:
         raise KeyError(self.__class__.__name__ + ' requires ' + property)
@@ -875,7 +875,7 @@ class XCObject(object):
     overwrite properties that have already been set."""
 
     defaults = {}
-    for property, attributes in self._schema.iteritems():
+    for property, attributes in self._schema.items():
       (is_list, property_type, is_strong, is_required) = attributes[0:4]
       if is_required and len(attributes) >= 5 and \
           not property in self._properties:
@@ -1426,7 +1426,7 @@ class XCFileLikeElement(XCHierarchicalElement):
     xche = self
     while xche != None and isinstance(xche, XCHierarchicalElement):
       xche_hashables = xche.Hashables()
-      for index in xrange(0, len(xche_hashables)):
+      for index in range(0, len(xche_hashables)):
         hashables.insert(index, xche_hashables[index])
       xche = xche.parent
     return hashables
@@ -2126,8 +2126,8 @@ class PBXContainerItemProxy(XCObject):
 
   def __repr__(self):
     props = self._properties
-    name = '%s.gyp:%s' % (props['containerPortal'].Name(), props['remoteInfo'])
-    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+    name = '{}.gyp:{}'.format(props['containerPortal'].Name(), props['remoteInfo'])
+    return '<{} {!r} at 0x{:x}>'.format(self.__class__.__name__, name, id(self))
 
   def Name(self):
     # Admittedly not the best name, but it's what Xcode uses.
@@ -2162,7 +2162,7 @@ class PBXTargetDependency(XCObject):
 
   def __repr__(self):
     name = self._properties.get('name') or self._properties['target'].Name()
-    return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+    return '<{} {!r} at 0x{:x}>'.format(self.__class__.__name__, name, id(self))
 
   def Name(self):
     # Admittedly not the best name, but it's what Xcode uses.
@@ -2468,7 +2468,7 @@ class PBXNativeTarget(XCTarget):
       # The headers phase should come before the resources, sources, and
       # frameworks phases, if any.
       insert_at = len(self._properties['buildPhases'])
-      for index in xrange(0, len(self._properties['buildPhases'])):
+      for index in range(0, len(self._properties['buildPhases'])):
         phase = self._properties['buildPhases'][index]
         if isinstance(phase, PBXResourcesBuildPhase) or \
            isinstance(phase, PBXSourcesBuildPhase) or \
@@ -2489,7 +2489,7 @@ class PBXNativeTarget(XCTarget):
       # The resources phase should come before the sources and frameworks
       # phases, if any.
       insert_at = len(self._properties['buildPhases'])
-      for index in xrange(0, len(self._properties['buildPhases'])):
+      for index in range(0, len(self._properties['buildPhases'])):
         phase = self._properties['buildPhases'][index]
         if isinstance(phase, PBXSourcesBuildPhase) or \
            isinstance(phase, PBXFrameworksBuildPhase):
@@ -2911,7 +2911,7 @@ class PBXProject(XCContainerPortal):
       # determine the sort order.
       return cmp(x_index, y_index)
 
-    for other_pbxproject, ref_dict in self._other_pbxprojects.iteritems():
+    for other_pbxproject, ref_dict in self._other_pbxprojects.items():
       # Build up a list of products in the remote project file, ordered the
       # same as the targets that produce them.
       remote_products = []
@@ -2956,7 +2956,7 @@ class XCProjectFile(XCObject):
       self._XCPrint(file, 0, '{ ')
     else:
       self._XCPrint(file, 0, '{\n')
-    for property, value in sorted(self._properties.iteritems(),
+    for property, value in sorted(self._properties.items(),
                                   cmp=lambda x, y: cmp(x, y)):
       if property == 'objects':
         self._PrintObjects(file)
diff --git a/media/webrtc/trunk/tools/gyp/pylib/gyp/xml_fix.py b/media/webrtc/trunk/tools/gyp/pylib/gyp/xml_fix.py
index 5de848158d..08c2073639 100644
--- a/media/webrtc/trunk/tools/gyp/pylib/gyp/xml_fix.py
+++ b/media/webrtc/trunk/tools/gyp/pylib/gyp/xml_fix.py
@@ -32,7 +32,7 @@ def _Replacement_writexml(self, writer, indent="", addindent="", newl=""):
   writer.write(indent+"<" + self.tagName)
 
   attrs = self._get_attributes()
-  a_names = attrs.keys()
+  a_names = list(attrs.keys())
   a_names.sort()
 
   for a_name in a_names:
@@ -43,12 +43,12 @@ def _Replacement_writexml(self, writer, indent="", addindent="", newl=""):
     writer.write(">%s" % newl)
     for node in self.childNodes:
       node.writexml(writer, indent + addindent, addindent, newl)
-    writer.write("%s</%s>%s" % (indent, self.tagName, newl))
+    writer.write("{}</{}>{}".format(indent, self.tagName, newl))
   else:
     writer.write("/>%s" % newl)
 
 
-class XmlFix(object):
+class XmlFix:
   """Object to manage temporary patching of xml.dom.minidom."""
 
   def __init__(self):
diff --git a/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/gyptest-action.py b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/gyptest-action.py
index ebc7f4fd94..fd2870e73b 100755
--- a/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/gyptest-action.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs-with-dependencies/gyptest-action.py
@@ -10,13 +10,14 @@ Verifies actions with multiple outputs & dependncies will correctly rebuild.
 This is a regression test for crrev.com/1177163002.
 """
 
+from __future__ import print_function
 import TestGyp
 import os
 import sys
 import time
 
 if sys.platform in ('darwin', 'win32'):
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 test = TestGyp.TestGyp()
diff --git a/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/gyptest-multiple-outputs.py b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/gyptest-multiple-outputs.py
index 72a7040a01..d552d36594 100755
--- a/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/gyptest-multiple-outputs.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple-outputs/gyptest-multiple-outputs.py
@@ -8,12 +8,13 @@
 Verifies actions with multiple outputs will correctly rebuild.
 """
 
+from __future__ import print_function
 import TestGyp
 import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 test = TestGyp.TestGyp()
diff --git a/media/webrtc/trunk/tools/gyp/test/actions-multiple/src/filter.py b/media/webrtc/trunk/tools/gyp/test/actions-multiple/src/filter.py
index f61a5fa59a..36a9dc7be3 100755
--- a/media/webrtc/trunk/tools/gyp/test/actions-multiple/src/filter.py
+++ b/media/webrtc/trunk/tools/gyp/test/actions-multiple/src/filter.py
@@ -6,7 +6,7 @@
 
 import sys
 
-data = open(sys.argv[3], 'r').read()
+data = open(sys.argv[3]).read()
 fh = open(sys.argv[4], 'w')
 fh.write(data.replace(sys.argv[1], sys.argv[2]))
 fh.close()
diff --git a/media/webrtc/trunk/tools/gyp/test/analyzer/gyptest-analyzer.py b/media/webrtc/trunk/tools/gyp/test/analyzer/gyptest-analyzer.py
index 72de21813c..5f2f1bef4d 100644
--- a/media/webrtc/trunk/tools/gyp/test/analyzer/gyptest-analyzer.py
+++ b/media/webrtc/trunk/tools/gyp/test/analyzer/gyptest-analyzer.py
@@ -32,7 +32,7 @@ def _CreateBogusConfigFile():
 
 
 def _ReadOutputFileContents():
-  f = open('analyzer_output', 'r')
+  f = open('analyzer_output')
   result = json.load(f)
   f.close()
   return result
@@ -75,57 +75,57 @@ def EnsureContains(matched=False, compile_targets=set(), test_targets=set()):
   """Verifies output contains |compile_targets|."""
   result = _ReadOutputFileContents()
   if 'error' in result:
-    print 'unexpected error', result.get('error')
+    print('unexpected error', result.get('error'))
     test.fail_test()
 
   if 'invalid_targets' in result:
-    print 'unexpected invalid_targets', result.get('invalid_targets')
+    print('unexpected invalid_targets', result.get('invalid_targets'))
     test.fail_test()
 
   actual_compile_targets = set(result['compile_targets'])
   if actual_compile_targets != compile_targets:
-    print 'actual compile_targets:', actual_compile_targets, \
-           '\nexpected compile_targets:', compile_targets
+    print('actual compile_targets:', actual_compile_targets, \
+           '\nexpected compile_targets:', compile_targets)
     test.fail_test()
 
   actual_test_targets = set(result['test_targets'])
   if actual_test_targets != test_targets:
-    print 'actual test_targets:', actual_test_targets, \
-           '\nexpected test_targets:', test_targets
+    print('actual test_targets:', actual_test_targets, \
+           '\nexpected test_targets:', test_targets)
     test.fail_test()
 
   if matched and result['status'] != found:
-    print 'expected', found, 'got', result['status']
+    print('expected', found, 'got', result['status'])
     test.fail_test()
   elif not matched and result['status'] != not_found:
-    print 'expected', not_found, 'got', result['status']
+    print('expected', not_found, 'got', result['status'])
     test.fail_test()
 
 
 def EnsureMatchedAll(compile_targets, test_targets=set()):
   result = _ReadOutputFileContents()
   if 'error' in result:
-    print 'unexpected error', result.get('error')
+    print('unexpected error', result.get('error'))
     test.fail_test()
 
   if 'invalid_targets' in result:
-    print 'unexpected invalid_targets', result.get('invalid_targets')
+    print('unexpected invalid_targets', result.get('invalid_targets'))
     test.fail_test()
 
   if result['status'] != found_all:
-    print 'expected', found_all, 'got', result['status']
+    print('expected', found_all, 'got', result['status'])
     test.fail_test()
 
   actual_compile_targets = set(result['compile_targets'])
   if actual_compile_targets != compile_targets:
-    print ('actual compile_targets:', actual_compile_targets,
-           '\nexpected compile_targets:', compile_targets)
+    print(('actual compile_targets:', actual_compile_targets,
+           '\nexpected compile_targets:', compile_targets))
     test.fail_test()
 
   actual_test_targets = set(result['test_targets'])
   if actual_test_targets != test_targets:
-    print ('actual test_targets:', actual_test_targets,
-           '\nexpected test_targets:', test_targets)
+    print(('actual test_targets:', actual_test_targets,
+           '\nexpected test_targets:', test_targets))
     test.fail_test()
 
 
@@ -133,15 +133,15 @@ def EnsureError(expected_error_string):
   """Verifies output contains the error string."""
   result = _ReadOutputFileContents()
   if result.get('error', '').find(expected_error_string) == -1:
-    print 'actual error:', result.get('error', ''), '\nexpected error:', \
-        expected_error_string
+    print('actual error:', result.get('error', ''), '\nexpected error:', \
+        expected_error_string)
     test.fail_test()
 
 
 def EnsureStdoutContains(expected_error_string):
   if test.stdout().find(expected_error_string) == -1:
-    print 'actual stdout:', test.stdout(), '\nexpected stdout:', \
-        expected_error_string
+    print('actual stdout:', test.stdout(), '\nexpected stdout:', \
+        expected_error_string)
     test.fail_test()
 
 
@@ -150,8 +150,8 @@ def EnsureInvalidTargets(expected_invalid_targets):
   result = _ReadOutputFileContents()
   actual_invalid_targets = set(result['invalid_targets'])
   if actual_invalid_targets != expected_invalid_targets:
-    print 'actual invalid_targets:', actual_invalid_targets, \
-        '\nexpected :', expected_invalid_targets
+    print('actual invalid_targets:', actual_invalid_targets, \
+        '\nexpected :', expected_invalid_targets)
     test.fail_test()
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/arflags/gyptest-arflags.py b/media/webrtc/trunk/tools/gyp/test/arflags/gyptest-arflags.py
index a5cbcac77d..36248fd63b 100644
--- a/media/webrtc/trunk/tools/gyp/test/arflags/gyptest-arflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/arflags/gyptest-arflags.py
@@ -13,7 +13,7 @@ import sys
 import TestGyp
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py
index d58fc7c2f9..500c7a56f7 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/gyptest-compiler-global-settings.py
@@ -66,7 +66,7 @@ test.must_contain_all_lines(test.stdout(), ['my_cc.py', 'my_cxx.py', 'BAR'])
 
 # Check that CC_host overrides make_global_settings
 old_env = dict(os.environ)
-os.environ['CC_host'] = '%s %s/my_cc.py SECRET' % (replacements['PYTHON'],
+os.environ['CC_host'] = '{} {}/my_cc.py SECRET'.format(replacements['PYTHON'],
                                                    replacements['PWD'])
 test.run_gyp(gypfile)
 os.environ.clear()
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cc.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cc.py
index e2f0bdd51c..b4d9e32b8b 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cc.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cc.py
@@ -3,4 +3,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cxx.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cxx.py
index e2f0bdd51c..b4d9e32b8b 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cxx.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_cxx.py
@@ -3,4 +3,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_ld.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_ld.py
index e2f0bdd51c..b4d9e32b8b 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_ld.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_ld.py
@@ -3,4 +3,4 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_nm.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_nm.py
index f0f1efcf73..578d680bc5 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_nm.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_nm.py
@@ -3,6 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
 with open('RAN_MY_NM', 'w') as f:
   f.write('RAN_MY_NM')
diff --git a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_readelf.py b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_readelf.py
index 40e303cd76..6ec7c9ea22 100755
--- a/media/webrtc/trunk/tools/gyp/test/compiler-override/my_readelf.py
+++ b/media/webrtc/trunk/tools/gyp/test/compiler-override/my_readelf.py
@@ -3,6 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
 with open('RAN_MY_READELF', 'w') as f:
   f.write('RAN_MY_READELF')
diff --git a/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/gyptest-duplicates.py b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/gyptest-duplicates.py
index 46687b4549..ebf5a5791f 100755
--- a/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/gyptest-duplicates.py
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/inheritance/gyptest-duplicates.py
@@ -27,7 +27,7 @@ contents = test.read('duplicates.gypd').replace(
     '\r', '').replace('\\\\', '/')
 expect = test.read('duplicates.gypd.golden').replace('\r', '')
 if not test.match(contents, expect):
-  print "Unexpected contents of `duplicates.gypd'"
+  print("Unexpected contents of `duplicates.gypd'")
   test.diff(expect, contents, 'duplicates.gypd ')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py b/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py
index ae4e9e5a2d..9e25864989 100755
--- a/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py
+++ b/media/webrtc/trunk/tools/gyp/test/configurations/target_platform/gyptest-target_platform.py
@@ -15,7 +15,7 @@ import TestCommon
 def RunX64(exe, stdout):
   try:
     test.run_built_executable(exe, stdout=stdout)
-  except WindowsError, e:
+  except OSError as e:
     # Assume the exe is 64-bit if it can't load on 32-bit systems.
     # Both versions of the error are required because different versions
     # of python seem to return different errors for invalid exe type.
diff --git a/media/webrtc/trunk/tools/gyp/test/copies/gyptest-updir.py b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-updir.py
index a34ae70723..19012d6d27 100755
--- a/media/webrtc/trunk/tools/gyp/test/copies/gyptest-updir.py
+++ b/media/webrtc/trunk/tools/gyp/test/copies/gyptest-updir.py
@@ -14,7 +14,7 @@ import sys
 import TestGyp
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 test = TestGyp.TestGyp()
diff --git a/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-solibs.py b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-solibs.py
index de9588db1c..309ce6d9a0 100644
--- a/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-solibs.py
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/gyptest-solibs.py
@@ -28,7 +28,7 @@ if test.format == 'ninja':
     if base1 != contents1:
       test.fail_test()
     if base2 != contents2:
-      print base2
+      print(base2)
       test.fail_test()
 
   del os.environ["PYTHONHASHSEED"]
diff --git a/media/webrtc/trunk/tools/gyp/test/determinism/rule.py b/media/webrtc/trunk/tools/gyp/test/determinism/rule.py
index 310a98192c..befec608ff 100644
--- a/media/webrtc/trunk/tools/gyp/test/determinism/rule.py
+++ b/media/webrtc/trunk/tools/gyp/test/determinism/rule.py
@@ -1,3 +1,5 @@
 #!/usr/bin/env python
 
-print 'Hello World'
+#!/usr/bin/env python
+
+print('Hello World')
diff --git a/media/webrtc/trunk/tools/gyp/test/escaping/gyptest-colon.py b/media/webrtc/trunk/tools/gyp/test/escaping/gyptest-colon.py
index 61a0e245f9..0f4a68a7c7 100644
--- a/media/webrtc/trunk/tools/gyp/test/escaping/gyptest-colon.py
+++ b/media/webrtc/trunk/tools/gyp/test/escaping/gyptest-colon.py
@@ -9,11 +9,12 @@ Tests that filenames that contain colons are handled correctly.
 (This is important for absolute paths on Windows.)
 """
 
+from __future__ import print_function
 import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py
index 8d19eedbed..38f4f6fce2 100644
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/gyptest-mac-bundle.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=[])
diff --git a/media/webrtc/trunk/tools/gyp/test/generator-output/rules/copy-file.py b/media/webrtc/trunk/tools/gyp/test/generator-output/rules/copy-file.py
index 938c336adb..8e513f6bbe 100755
--- a/media/webrtc/trunk/tools/gyp/test/generator-output/rules/copy-file.py
+++ b/media/webrtc/trunk/tools/gyp/test/generator-output/rules/copy-file.py
@@ -6,7 +6,7 @@
 
 import sys
 
-contents = open(sys.argv[1], 'r').read()
+contents = open(sys.argv[1]).read()
 open(sys.argv[2], 'wb').write(contents)
 
 sys.exit(0)
diff --git a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios.py b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios.py
index f9052549d0..da33c054b9 100755
--- a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios.py
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-app-ios.py
@@ -17,13 +17,13 @@ def CheckFileXMLPropertyList(file):
   output = subprocess.check_output(['file', file])
   # The double space after XML is intentional.
   if not 'XML  document text' in output:
-    print 'File: Expected XML  document text, got %s' % output
+    print('File: Expected XML  document text, got %s' % output)
     test.fail_test()
 
 def CheckFileBinaryPropertyList(file):
   output = subprocess.check_output(['file', file])
   if not 'Apple binary property list' in output:
-    print 'File: Expected Apple binary property list, got %s' % output
+    print('File: Expected Apple binary property list, got %s' % output)
     test.fail_test()
 
 if sys.platform == 'darwin':
diff --git a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-archs.py b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-archs.py
index c653d997ad..daf2e014db 100644
--- a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-archs.py
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-archs.py
@@ -48,7 +48,7 @@ if sys.platform == 'darwin':
         kwds['arguments'].extend(['-arch', archs[0]])
 
     test.set_configuration(configuration)
-    filename = '%s.app/%s' % (target, target)
+    filename = '{}.app/{}'.format(target, target)
     test.build('test-archs.gyp', target, chdir='app-bundle', **kwds)
     result_file = test.built_file_path(filename, chdir='app-bundle')
 
diff --git a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-extension.py b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-extension.py
index c5e76d93ff..ed313ffe01 100755
--- a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-extension.py
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-extension.py
@@ -15,12 +15,12 @@ import sys
 
 def CheckStrip(p, expected):
   if expected not in subprocess.check_output(['nm','-gU', p]):
-    print expected + " shouldn't get stripped out."
+    print(expected + " shouldn't get stripped out.")
     test.fail_test()
 
 def CheckEntrypoint(p, expected):
   if expected not in subprocess.check_output(['nm', p]):
-    print expected + "not found."
+    print(expected + "not found.")
     test.fail_test()
 
 if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0600":
diff --git a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-per-config-settings.py b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-per-config-settings.py
index 7313e56343..6371509ac4 100644
--- a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-per-config-settings.py
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-per-config-settings.py
@@ -22,7 +22,7 @@ def CheckFileType(file, expected):
   o = proc.communicate()[0].strip()
   assert not proc.returncode
   if not expected in o:
-    print 'File: Expected %s, got %s' % (expected, o)
+    print('File: Expected {}, got {}'.format(expected, o))
     test.fail_test()
 
 def HasCerts():
@@ -37,7 +37,7 @@ def CheckSignature(file):
   o = proc.communicate()[0].strip()
   assert not proc.returncode
   if "code object is not signed at all" in o:
-    print 'File %s not properly signed.' % (file)
+    print('File %s not properly signed.' % (file))
     test.fail_test()
 
 def CheckEntitlements(file, expected_entitlements):
@@ -49,10 +49,10 @@ def CheckEntitlements(file, expected_entitlements):
     data = temp.read()
   entitlements = ParseEntitlements(data)
   if not entitlements:
-    print 'No valid entitlements found in %s.' % (file)
+    print('No valid entitlements found in %s.' % (file))
     test.fail_test()
   if entitlements != expected_entitlements:
-    print 'Unexpected entitlements found in %s.' % (file)
+    print('Unexpected entitlements found in %s.' % (file))
     test.fail_test()
 
 def ParseEntitlements(data):
@@ -75,17 +75,17 @@ def GetMachineBuild():
 
 def CheckPlistvalue(plist, key, expected):
   if key not in plist:
-    print '%s not set in plist' % key
+    print('%s not set in plist' % key)
     test.fail_test()
     return
   actual = plist[key]
   if actual != expected:
-    print 'File: Expected %s, got %s for %s' % (expected, actual, key)
+    print('File: Expected {}, got {} for {}'.format(expected, actual, key))
     test.fail_test()
 
 def CheckPlistNotSet(plist, key):
   if key in plist:
-    print '%s should not be set in plist' % key
+    print('%s should not be set in plist' % key)
     test.fail_test()
     return
 
@@ -111,7 +111,7 @@ if sys.platform == 'darwin':
     xcode_version = TestMac.Xcode.Version()
     if xcode_version >= '0720':
       if len(plist) != 23:
-        print 'plist should have 23 entries, but it has %s' % len(plist)
+        print('plist should have 23 entries, but it has %s' % len(plist))
         test.fail_test()
 
     # Values that will hopefully never change.
diff --git a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-watch.py b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-watch.py
index f5c4601d81..885637421a 100755
--- a/media/webrtc/trunk/tools/gyp/test/ios/gyptest-watch.py
+++ b/media/webrtc/trunk/tools/gyp/test/ios/gyptest-watch.py
@@ -14,7 +14,7 @@ import TestMac
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/lib/TestCmd.py b/media/webrtc/trunk/tools/gyp/test/lib/TestCmd.py
index da27cc8288..850d933dbc 100644
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestCmd.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestCmd.py
@@ -226,6 +226,7 @@ import shutil
 import stat
 import string
 import sys
+import atexit
 import tempfile
 import time
 import traceback
@@ -250,7 +251,7 @@ except ImportError:
     __all__.append('simple_diff')
 
 def is_List(e):
-    return type(e) is types.ListType \
+    return type(e) is list \
         or isinstance(e, UserList.UserList)
 
 try:
@@ -261,12 +262,12 @@ except ImportError:
 
 if hasattr(types, 'UnicodeType'):
     def is_String(e):
-        return type(e) is types.StringType \
-            or type(e) is types.UnicodeType \
+        return type(e) is bytes \
+            or type(e) is str \
             or isinstance(e, UserString)
 else:
     def is_String(e):
-        return type(e) is types.StringType or isinstance(e, UserString)
+        return type(e) is bytes or isinstance(e, UserString)
 
 tempfile.template = 'testcmd.'
 if os.name in ('posix', 'nt'):
@@ -274,7 +275,7 @@ if os.name in ('posix', 'nt'):
 else:
     tempfile.template = 'testcmd.'
 
-re_space = re.compile('\s')
+re_space = re.compile(r'\s')
 
 _Cleanup = []
 
@@ -282,7 +283,7 @@ _chain_to_exitfunc = None
 
 def _clean():
     global _Cleanup
-    cleanlist = filter(None, _Cleanup)
+    cleanlist = [_f for _f in _Cleanup if _f]
     del _Cleanup[:]
     cleanlist.reverse()
     for test in cleanlist:
@@ -298,7 +299,7 @@ except ImportError:
         _chain_to_exitfunc = sys.exitfunc
     except AttributeError:
         pass
-    sys.exitfunc = _clean
+    atexit.register(_clean)
 else:
     atexit.register(_clean)
 
@@ -307,7 +308,7 @@ try:
 except NameError:
     def zip(*lists):
         result = []
-        for i in xrange(min(map(len, lists))):
+        for i in range(min(list(map(len, lists)))):
             result.append(tuple(map(lambda l, i=i: l[i], lists)))
         return result
 
@@ -316,7 +317,7 @@ class Collector:
         self.entries = [top]
     def __call__(self, arg, dirname, names):
         pathjoin = lambda n, d=dirname: os.path.join(d, n)
-        self.entries.extend(map(pathjoin, names))
+        self.entries.extend(list(map(pathjoin, names)))
 
 def _caller(tblist, skip):
     string = ""
@@ -433,9 +434,9 @@ def match_re(lines = None, res = None):
         s = "^" + res[i] + "$"
         try:
             expr = re.compile(s)
-        except re.error, e:
+        except re.error as e:
             msg = "Regular expression error in %s: %s"
-            raise re.error, msg % (repr(s), e[0])
+            raise re.error(msg % (repr(s), e[0]))
         if not expr.search(lines[i]):
             return
     return 1
@@ -443,16 +444,16 @@ def match_re(lines = None, res = None):
 def match_re_dotall(lines = None, res = None):
     """
     """
-    if not type(lines) is type(""):
+    if not type(lines) is str:
         lines = string.join(lines, "\n")
-    if not type(res) is type(""):
+    if not type(res) is str:
         res = string.join(res, "\n")
     s = "^" + res + "$"
     try:
         expr = re.compile(s, re.DOTALL)
-    except re.error, e:
+    except re.error as e:
         msg = "Regular expression error in %s: %s"
-        raise re.error, msg % (repr(s), e[0])
+        raise re.error(msg % (repr(s), e[0]))
     if expr.match(lines):
         return 1
 
@@ -470,20 +471,20 @@ else:
         """
         sm = difflib.SequenceMatcher(None, a, b)
         def comma(x1, x2):
-            return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
+            return x1+1 == x2 and str(x2) or '{},{}'.format(x1+1, x2)
         result = []
         for op, a1, a2, b1, b2 in sm.get_opcodes():
             if op == 'delete':
                 result.append("%sd%d" % (comma(a1, a2), b1))
-                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+                result.extend(['< ' + l for l in a[a1:a2]])
             elif op == 'insert':
                 result.append("%da%s" % (a1, comma(b1, b2)))
-                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+                result.extend(['> ' + l for l in b[b1:b2]])
             elif op == 'replace':
-                result.append("%sc%s" % (comma(a1, a2), comma(b1, b2)))
-                result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+                result.append("{}c{}".format(comma(a1, a2), comma(b1, b2)))
+                result.extend(['< ' + l for l in a[a1:a2]])
                 result.append('---')
-                result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+                result.extend(['> ' + l for l in b[b1:b2]])
         return result
 
 def diff_re(a, b, fromfile='', tofile='',
@@ -506,11 +507,11 @@ def diff_re(a, b, fromfile='', tofile='',
         s = "^" + aline + "$"
         try:
             expr = re.compile(s)
-        except re.error, e:
+        except re.error as e:
             msg = "Regular expression error in %s: %s"
-            raise re.error, msg % (repr(s), e[0])
+            raise re.error(msg % (repr(s), e[0]))
         if not expr.search(bline):
-            result.append("%sc%s" % (i+1, i+1))
+            result.append("{}c{}".format(i+1, i+1))
             result.append('< ' + repr(a[i]))
             result.append('---')
             result.append('> ' + repr(b[i]))
@@ -564,7 +565,7 @@ else:
                     st = os.stat(f)
                 except OSError:
                     continue
-                if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
+                if stat.S_IMODE(st[stat.ST_MODE]) & 0o111:
                     return f
         return None
 
@@ -652,14 +653,14 @@ except ImportError:
             universal_newlines = 1
             def __init__(self, command, **kw):
                 if kw.get('stderr') == 'STDOUT':
-                    apply(popen2.Popen4.__init__, (self, command, 1))
+                    popen2.Popen4.__init__(*(self, command, 1))
                 else:
-                    apply(popen2.Popen3.__init__, (self, command, 1))
+                    popen2.Popen3.__init__(*(self, command, 1))
                 self.stdin = self.tochild
                 self.stdout = self.fromchild
                 self.stderr = self.childerr
             def wait(self, *args, **kw):
-                resultcode = apply(popen2.Popen3.wait, (self,)+args, kw)
+                resultcode = popen2.Popen3.wait(*(self,)+args, **kw)
                 if os.WIFEXITED(resultcode):
                     return os.WEXITSTATUS(resultcode)
                 elif os.WIFSIGNALED(resultcode):
@@ -722,7 +723,7 @@ class Popen(subprocess.Popen):
                 (errCode, written) = WriteFile(x, input)
             except ValueError:
                 return self._close('stdin')
-            except (subprocess.pywintypes.error, Exception), why:
+            except (subprocess.pywintypes.error, Exception) as why:
                 if why[0] in (109, errno.ESHUTDOWN):
                     return self._close('stdin')
                 raise
@@ -743,7 +744,7 @@ class Popen(subprocess.Popen):
                     (errCode, read) = ReadFile(x, nAvail, None)
             except ValueError:
                 return self._close(which)
-            except (subprocess.pywintypes.error, Exception), why:
+            except (subprocess.pywintypes.error, Exception) as why:
                 if why[0] in (109, errno.ESHUTDOWN):
                     return self._close(which)
                 raise
@@ -762,7 +763,7 @@ class Popen(subprocess.Popen):
 
             try:
                 written = os.write(self.stdin.fileno(), input)
-            except OSError, why:
+            except OSError as why:
                 if why[0] == errno.EPIPE: #broken pipe
                     return self._close('stdin')
                 raise
@@ -839,7 +840,7 @@ except NameError:
 
 
 
-class TestCmd(object):
+class TestCmd:
     """Class TestCmd
     """
 
@@ -882,7 +883,7 @@ class TestCmd(object):
                 #self.diff_function = difflib.unified_diff
         self._dirlist = []
         self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
-        if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
+        if 'PRESERVE' in os.environ and not os.environ['PRESERVE'] == '':
             self._preserve['pass_test'] = os.environ['PRESERVE']
             self._preserve['fail_test'] = os.environ['PRESERVE']
             self._preserve['no_result'] = os.environ['PRESERVE']
@@ -947,7 +948,7 @@ class TestCmd(object):
 
     def canonicalize(self, path):
         if is_List(path):
-            path = apply(os.path.join, tuple(path))
+            path = os.path.join(*tuple(path))
         if not os.path.isabs(path):
             path = os.path.join(self.workdir, path)
         return path
@@ -981,7 +982,7 @@ class TestCmd(object):
             condition = self.condition
         if self._preserve[condition]:
             for dir in self._dirlist:
-                print "Preserved directory", dir
+                print("Preserved directory", dir)
         else:
             list = self._dirlist[:]
             list.reverse()
@@ -1000,7 +1001,7 @@ class TestCmd(object):
                            interpreter = None,
                            arguments = None):
         if program:
-            if type(program) == type('') and not os.path.isabs(program):
+            if type(program) == str and not os.path.isabs(program):
                 program = os.path.join(self._cwd, program)
         else:
             program = self.program
@@ -1014,7 +1015,7 @@ class TestCmd(object):
                 interpreter = [interpreter]
             cmd = list(interpreter) + cmd
         if arguments:
-            if type(arguments) == type(''):
+            if type(arguments) == str:
                 arguments = string.split(arguments)
             cmd.extend(arguments)
         return cmd
@@ -1028,17 +1029,17 @@ class TestCmd(object):
         difflib
     except NameError:
         def diff(self, a, b, name, *args, **kw):
-            print self.banner('Expected %s' % name)
-            print a
-            print self.banner('Actual %s' % name)
-            print b
+            print(self.banner('Expected %s' % name))
+            print(a)
+            print(self.banner('Actual %s' % name))
+            print(b)
     else:
         def diff(self, a, b, name, *args, **kw):
-            print self.banner(name)
+            print(self.banner(name))
             args = (a.splitlines(), b.splitlines()) + args
-            lines = apply(self.diff_function, args, kw)
+            lines = self.diff_function(*args, **kw)
             for l in lines:
-                print l
+                print(l)
 
     def fail_test(self, condition = 1, function = None, skip = 0):
         """Cause the test to fail.
@@ -1126,7 +1127,7 @@ class TestCmd(object):
         """
         file = self.canonicalize(file)
         if mode[0] != 'r':
-            raise ValueError, "mode must begin with 'r'"
+            raise ValueError("mode must begin with 'r'")
         with open(file, mode) as f:
             result = f.read()
         return result
@@ -1154,7 +1155,7 @@ class TestCmd(object):
         prepended unless it is enclosed in a [list].
         """
         cmd = self.command_args(program, interpreter, arguments)
-        cmd_string = string.join(map(self.escape, cmd), ' ')
+        cmd_string = string.join(list(map(self.escape, cmd)), ' ')
         if self.verbose:
             sys.stderr.write(cmd_string + "\n")
         if universal_newlines is None:
@@ -1319,7 +1320,7 @@ class TestCmd(object):
             if sub is None:
                 continue
             if is_List(sub):
-                sub = apply(os.path.join, tuple(sub))
+                sub = os.path.join(*tuple(sub))
             new = os.path.join(self.workdir, sub)
             try:
                 os.mkdir(new)
@@ -1409,7 +1410,7 @@ class TestCmd(object):
         """Find an executable file.
         """
         if is_List(file):
-            file = apply(os.path.join, tuple(file))
+            file = os.path.join(*tuple(file))
         if not os.path.isabs(file):
             file = where_is(file, path, pathext)
         return file
@@ -1431,7 +1432,7 @@ class TestCmd(object):
         the temporary working directory name with the specified
         arguments using the os.path.join() method.
         """
-        return apply(os.path.join, (self.workdir,) + tuple(args))
+        return os.path.join(*(self.workdir,) + tuple(args))
 
     def readable(self, top, read=1):
         """Make the specified directory tree readable (read == 1)
@@ -1508,12 +1509,12 @@ class TestCmd(object):
                 def do_chmod(fname):
                     try: st = os.stat(fname)
                     except OSError: pass
-                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200))
+                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0o200))
             else:
                 def do_chmod(fname):
                     try: st = os.stat(fname)
                     except OSError: pass
-                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200))
+                    else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0o200))
 
         if os.path.isfile(top):
             do_chmod(top)
@@ -1586,7 +1587,7 @@ class TestCmd(object):
         """
         file = self.canonicalize(file)
         if mode[0] != 'w':
-            raise ValueError, "mode must begin with 'w'"
+            raise ValueError("mode must begin with 'w'")
         with open(file, mode) as f:
             f.write(content)
 
diff --git a/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py b/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py
index a6e89ac32b..3e881168d8 100644
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestCommon.py
@@ -184,7 +184,7 @@ else:
     module_suffix = '.so'
 
 def is_List(e):
-    return type(e) is types.ListType \
+    return type(e) is list \
         or isinstance(e, UserList.UserList)
 
 def is_writable(f):
@@ -227,7 +227,7 @@ class TestCommon(TestCmd):
         calling the base class initialization, and then changing directory
         to the workdir.
         """
-        apply(TestCmd.__init__, [self], kw)
+        TestCmd.__init__(*[self], **kw)
         os.chdir(self.workdir)
 
     def must_be_writable(self, *files):
@@ -237,13 +237,13 @@ class TestCommon(TestCmd):
         them.  Exits FAILED if any of the files does not exist or is
         not writable.
         """
-        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        files = [is_List(x) and os.path.join(*x) or x for x in files]
         existing, missing = separate_files(files)
-        unwritable = filter(lambda x, iw=is_writable: not iw(x), existing)
+        unwritable = list(filter(lambda x, iw=is_writable: not iw(x), existing))
         if missing:
-            print "Missing files: `%s'" % string.join(missing, "', `")
+            print("Missing files: `%s'" % string.join(missing, "', `"))
         if unwritable:
-            print "Unwritable files: `%s'" % string.join(unwritable, "', `")
+            print("Unwritable files: `%s'" % string.join(unwritable, "', `"))
         self.fail_test(missing + unwritable)
 
     def must_contain(self, file, required, mode = 'rb'):
@@ -252,11 +252,11 @@ class TestCommon(TestCmd):
         file_contents = self.read(file, mode)
         contains = (string.find(file_contents, required) != -1)
         if not contains:
-            print "File `%s' does not contain required string." % file
-            print self.banner('Required string ')
-            print required
-            print self.banner('%s contents ' % file)
-            print file_contents
+            print("File `%s' does not contain required string." % file)
+            print(self.banner('Required string '))
+            print(required)
+            print(self.banner('%s contents ' % file))
+            print(file_contents)
             self.fail_test(not contains)
 
     def must_contain_all_lines(self, output, lines, title=None, find=None):
@@ -323,10 +323,10 @@ class TestCommon(TestCmd):
         pathname will be constructed by concatenating them.  Exits FAILED
         if any of the files does not exist.
         """
-        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
-        missing = filter(lambda x: not os.path.exists(x), files)
+        files = [is_List(x) and os.path.join(*x) or x for x in files]
+        missing = [x for x in files if not os.path.exists(x)]
         if missing:
-            print "Missing files: `%s'" % string.join(missing, "', `")
+            print("Missing files: `%s'" % string.join(missing, "', `"))
             self.fail_test(missing)
 
     def must_match(self, file, expect, mode = 'rb'):
@@ -341,7 +341,7 @@ class TestCommon(TestCmd):
         except KeyboardInterrupt:
             raise
         except:
-            print "Unexpected contents of `%s'" % file
+            print("Unexpected contents of `%s'" % file)
             self.diff(expect, file_contents, 'contents ')
             raise
 
@@ -351,11 +351,11 @@ class TestCommon(TestCmd):
         file_contents = self.read(file, mode)
         contains = (string.find(file_contents, banned) != -1)
         if contains:
-            print "File `%s' contains banned string." % file
-            print self.banner('Banned string ')
-            print banned
-            print self.banner('%s contents ' % file)
-            print file_contents
+            print("File `%s' contains banned string." % file)
+            print(self.banner('Banned string '))
+            print(banned)
+            print(self.banner('%s contents ' % file))
+            print(file_contents)
             self.fail_test(contains)
 
     def must_not_contain_any_line(self, output, lines, title=None, find=None):
@@ -395,10 +395,10 @@ class TestCommon(TestCmd):
         which case the pathname will be constructed by concatenating them.
         Exits FAILED if any of the files exists.
         """
-        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
-        existing = filter(os.path.exists, files)
+        files = [is_List(x) and os.path.join(*x) or x for x in files]
+        existing = list(filter(os.path.exists, files))
         if existing:
-            print "Unexpected files exist: `%s'" % string.join(existing, "', `")
+            print("Unexpected files exist: `%s'" % string.join(existing, "', `"))
             self.fail_test(existing)
 
     def must_not_be_writable(self, *files):
@@ -408,13 +408,13 @@ class TestCommon(TestCmd):
         them.  Exits FAILED if any of the files does not exist or is
         writable.
         """
-        files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+        files = [is_List(x) and os.path.join(*x) or x for x in files]
         existing, missing = separate_files(files)
-        writable = filter(is_writable, existing)
+        writable = list(filter(is_writable, existing))
         if missing:
-            print "Missing files: `%s'" % string.join(missing, "', `")
+            print("Missing files: `%s'" % string.join(missing, "', `"))
         if writable:
-            print "Writable files: `%s'" % string.join(writable, "', `")
+            print("Writable files: `%s'" % string.join(writable, "', `"))
         self.fail_test(missing + writable)
 
     def _complete(self, actual_stdout, expected_stdout,
@@ -427,21 +427,21 @@ class TestCommon(TestCmd):
             expect = ''
             if status != 0:
                 expect = " (expected %s)" % str(status)
-            print "%s returned %s%s" % (self.program, str(_status(self)), expect)
-            print self.banner('STDOUT ')
-            print actual_stdout
-            print self.banner('STDERR ')
-            print actual_stderr
+            print("{} returned {}{}".format(self.program, str(_status(self)), expect))
+            print(self.banner('STDOUT '))
+            print(actual_stdout)
+            print(self.banner('STDERR '))
+            print(actual_stderr)
             self.fail_test()
         if not expected_stdout is None and not match(actual_stdout, expected_stdout):
             self.diff(expected_stdout, actual_stdout, 'STDOUT ')
             if actual_stderr:
-                print self.banner('STDERR ')
-                print actual_stderr
+                print(self.banner('STDERR '))
+                print(actual_stderr)
             self.fail_test()
         if not expected_stderr is None and not match(actual_stderr, expected_stderr):
-            print self.banner('STDOUT ')
-            print actual_stdout
+            print(self.banner('STDOUT '))
+            print(actual_stdout)
             self.diff(expected_stderr, actual_stderr, 'STDERR ')
             self.fail_test()
 
@@ -463,20 +463,18 @@ class TestCommon(TestCmd):
                 arguments = options + " " + arguments
 
         try:
-            return apply(TestCmd.start,
-                         (self, program, interpreter, arguments, universal_newlines),
-                         kw)
+            return TestCmd.start(*(self, program, interpreter, arguments, universal_newlines), **kw)
         except KeyboardInterrupt:
             raise
-        except Exception, e:
-            print self.banner('STDOUT ')
+        except Exception as e:
+            print(self.banner('STDOUT '))
             try:
-                print self.stdout()
+                print(self.stdout())
             except IndexError:
                 pass
-            print self.banner('STDERR ')
+            print(self.banner('STDERR '))
             try:
-                print self.stderr()
+                print(self.stderr())
             except IndexError:
                 pass
             cmd_args = self.command_args(program, interpreter, arguments)
@@ -501,7 +499,7 @@ class TestCommon(TestCmd):
                         command.  A value of None means don't
                         test exit status.
         """
-        apply(TestCmd.finish, (self, popen,), kw)
+        TestCmd.finish(*(self, popen,), **kw)
         match = kw.get('match', self.match)
         self._complete(self.stdout(), stdout,
                        self.stderr(), stderr, status, match)
@@ -539,7 +537,7 @@ class TestCommon(TestCmd):
                 arguments = options + " " + arguments
         kw['arguments'] = arguments
         match = kw.pop('match', self.match)
-        apply(TestCmd.run, [self], kw)
+        TestCmd.run(*[self], **kw)
         self._complete(self.stdout(), stdout,
                        self.stderr(), stderr, status, match)
 
diff --git a/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py b/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py
index fc7b135817..01084d4fb4 100644
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestGyp.py
@@ -6,7 +6,9 @@
 TestGyp.py:  a testing framework for GYP integration tests.
 """
 
+from __future__ import print_function
 import collections
+import collections.abc
 from contextlib import contextmanager
 import itertools
 import os
@@ -282,13 +284,13 @@ class TestGypBase(TestCommon.TestCommon):
     that expect exact output from the command (make) can
     just set stdout= when they call the run_build() method.
     """
-    print "Build is not up-to-date:"
-    print self.banner('STDOUT ')
-    print self.stdout()
+    print("Build is not up-to-date:")
+    print(self.banner('STDOUT '))
+    print(self.stdout())
     stderr = self.stderr()
     if stderr:
-      print self.banner('STDERR ')
-      print stderr
+      print(self.banner('STDERR '))
+      print(stderr)
 
   def run_gyp(self, gyp_file, *args, **kw):
     """
@@ -326,7 +328,7 @@ class TestGypBase(TestCommon.TestCommon):
     the tool-specific subclasses or clutter the tests themselves
     with platform-specific code.
     """
-    if kw.has_key('SYMROOT'):
+    if 'SYMROOT' in kw:
       del kw['SYMROOT']
     super(TestGypBase, self).run(*args, **kw)
 
@@ -492,7 +494,7 @@ class TestGypCMake(TestGypBase):
     if status is None:
       kw['status'] = None
     else:
-      if not isinstance(status, collections.Iterable): status = (status,)
+      if not isinstance(status, collections.abc.Iterable): status = (status,)
       kw['status'] = list(itertools.chain((0,), status))
     self.cmake_build(gyp_file, target, **kw)
     kw['status'] = status
@@ -556,7 +558,7 @@ class TestGypMake(TestGypBase):
     # Makefile.gyp_filename), so use that if there is no Makefile.
     chdir = kw.get('chdir', '')
     if not os.path.exists(os.path.join(chdir, 'Makefile')):
-      print "NO Makefile in " + os.path.join(chdir, 'Makefile')
+      print("NO Makefile in " + os.path.join(chdir, 'Makefile'))
       arguments.insert(0, '-f')
       arguments.insert(1, os.path.splitext(gyp_file)[0] + '.Makefile')
     kw['arguments'] = arguments
@@ -663,7 +665,7 @@ def FindMSBuildInstallation(msvs_version = 'auto'):
 
   msbuild_basekey = r'HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions'
   if not registry.KeyExists(msbuild_basekey):
-    print 'Error: could not find MSBuild base registry entry'
+    print('Error: could not find MSBuild base registry entry')
     return None
 
   msbuild_version = None
@@ -672,7 +674,7 @@ def FindMSBuildInstallation(msvs_version = 'auto'):
     if registry.KeyExists(msbuild_basekey + '\\' + msbuild_test_version):
       msbuild_version = msbuild_test_version
     else:
-      print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+      print('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
              'but corresponding MSBuild "%s" was not found.' %
              (msvs_version, msbuild_version))
   if not msbuild_version:
@@ -682,13 +684,13 @@ def FindMSBuildInstallation(msvs_version = 'auto'):
         msbuild_version = msbuild_test_version
         break
   if not msbuild_version:
-    print 'Error: could not find MSBuild registry entry'
+    print('Error: could not find MSBuild registry entry')
     return None
 
   msbuild_path = registry.GetValue(msbuild_basekey + '\\' + msbuild_version,
                                    'MSBuildToolsPath')
   if not msbuild_path:
-    print 'Error: could not get MSBuild registry entry value'
+    print('Error: could not get MSBuild registry entry value')
     return None
 
   return os.path.join(msbuild_path, 'MSBuild.exe')
@@ -730,7 +732,7 @@ def FindVisualStudioInstallation():
         msbuild_path = FindMSBuildInstallation(msvs_version)
         return build_tool, uses_msbuild, msbuild_path
     else:
-      print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+      print('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
               'but corresponding "%s" was not found.' % (msvs_version, path))
   # Neither GYP_MSVS_VERSION nor the path help us out.  Iterate through
   # the choices looking for a match.
@@ -742,7 +744,7 @@ def FindVisualStudioInstallation():
         uses_msbuild = msvs_version >= '2010'
         msbuild_path = FindMSBuildInstallation(msvs_version)
         return build_tool, uses_msbuild, msbuild_path
-  print 'Error: could not find devenv'
+  print('Error: could not find devenv')
   sys.exit(1)
 
 class TestGypOnMSToolchain(TestGypBase):
@@ -887,10 +889,10 @@ class TestGypMSVS(TestGypOnMSToolchain):
     Verifies that a build of the specified Visual Studio target is up to date.
 
     Beware that VS2010 will behave strangely if you build under
-    C:\USERS\yourname\AppData\Local. It will cause needless work.  The ouptut
+    C:\USERS\\yourname\\AppData\\Local. It will cause needless work.  The ouptut
     will be "1 succeeded and 0 up to date".  MSBuild tracing reveals that:
-    "Project 'C:\Users\...\AppData\Local\...vcxproj' not up to date because
-    'C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 10.0\VC\BIN\1033\CLUI.DLL'
+    "Project 'C:\Users\\...\\AppData\\Local\\...vcxproj' not up to date because
+    'C:\\PROGRAM FILES (X86)\\MICROSOFT VISUAL STUDIO 10.0\\VC\\BIN\1033\\CLUI.DLL'
     was modified at 02/21/2011 17:03:30, which is newer than '' which was
     modified at 01/01/0001 00:00:00.
 
@@ -1190,4 +1192,4 @@ def TestGyp(*args, **kw):
   for format_class in format_class_list:
     if format == format_class.format:
       return format_class(*args, **kw)
-  raise Exception, "unknown format %r" % format
+  raise Exception("unknown format %r" % format)
diff --git a/media/webrtc/trunk/tools/gyp/test/lib/TestMac.py b/media/webrtc/trunk/tools/gyp/test/lib/TestMac.py
index 68605d77b1..4db31f0cff 100644
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestMac.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestMac.py
@@ -23,17 +23,17 @@ def CheckFileType(test, file, archs):
     pattern = re.compile('^Architectures in the fat file: (.*) are: (.*)$')
   match = pattern.match(o)
   if match is None:
-    print 'Ouput does not match expected pattern: %s' % (pattern.pattern)
+    print('Ouput does not match expected pattern: %s' % (pattern.pattern))
     test.fail_test()
   else:
     found_file, found_archs = match.groups()
     if found_file != file or set(found_archs.split()) != set(archs):
-      print 'Expected file %s with arch %s, got %s with arch %s' % (
-          file, ' '.join(archs), found_file, found_archs)
+      print('Expected file {} with arch {}, got {} with arch {}'.format(
+          file, ' '.join(archs), found_file, found_archs))
       test.fail_test()
 
 
-class XcodeInfo(object):
+class XcodeInfo:
   """Simplify access to Xcode informations."""
 
   def __init__(self):
diff --git a/media/webrtc/trunk/tools/gyp/test/lib/TestWin.py b/media/webrtc/trunk/tools/gyp/test/lib/TestWin.py
index 7627197b1f..62b5f5e30a 100644
--- a/media/webrtc/trunk/tools/gyp/test/lib/TestWin.py
+++ b/media/webrtc/trunk/tools/gyp/test/lib/TestWin.py
@@ -12,7 +12,7 @@ import re
 import sys
 import subprocess
 
-class Registry(object):
+class Registry:
   def _QueryBase(self, sysdir, key, value):
     """Use reg.exe to read a particular key.
 
@@ -63,7 +63,7 @@ class Registry(object):
     text = None
     try:
       text = self._QueryBase('Sysnative', key, value)
-    except OSError, e:
+    except OSError as e:
       if e.errno == errno.ENOENT:
         text = self._QueryBase('System32', key, value)
       else:
diff --git a/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/check-ldflags.py b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/check-ldflags.py
index 0515da95e4..0a7d25efc3 100755
--- a/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/check-ldflags.py
+++ b/media/webrtc/trunk/tools/gyp/test/linux/ldflags-duplicates/check-ldflags.py
@@ -12,13 +12,13 @@ import sys
 
 def CheckContainsFlags(args, substring):
   if args.find(substring) is -1:
-    print 'ERROR: Linker arguments "%s" are missing in "%s"' % (substring, args)
+    print('ERROR: Linker arguments "{}" are missing in "{}"'.format(substring, args))
     return False;
   return True;
 
 if __name__ == '__main__':
   args = " ".join(sys.argv)
-  print  "args = " +args
+  print("args = " +args)
   if not CheckContainsFlags(args, 'lib1.a -Wl,--no-whole-archive') \
     or not CheckContainsFlags(args, 'lib2.a -Wl,--no-whole-archive'):
     sys.exit(1);
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-assets-catalog.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-assets-catalog.py
index ca76b513aa..1a352c8874 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-assets-catalog.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-assets-catalog.py
@@ -17,12 +17,12 @@ import subprocess
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 def ExpectEq(expected, actual):
   if expected != actual:
-    print >>sys.stderr, 'Expected "%s", got "%s"' % (expected, actual)
+    print('Expected "{}", got "{}"'.format(expected, actual), file=sys.stderr)
     test.fail_test()
 
 def ls(path):
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-error.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-error.py
index c6fe33f128..f70488c387 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-error.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app-error.py
@@ -14,7 +14,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   expected_error = 'Old-style plist parser: missing semicolon in dictionary'
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py
index be92d01aed..9cea21a997 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-app.py
@@ -18,7 +18,7 @@ import sys
 
 
 if sys.platform in ('darwin', 'win32'):
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
@@ -26,12 +26,12 @@ def CheckFileXMLPropertyList(file):
   output = subprocess.check_output(['file', file])
   # The double space after XML is intentional.
   if not 'XML  document text' in output:
-    print 'File: Expected XML  document text, got %s' % output
+    print('File: Expected XML  document text, got %s' % output)
     test.fail_test()
 
 def ExpectEq(expected, actual):
   if expected != actual:
-    print >>sys.stderr, 'Expected "%s", got "%s"' % (expected, actual)
+    print('Expected "{}", got "{}"'.format(expected, actual), file=sys.stderr)
     test.fail_test()
 
 def ls(path):
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-bundle-resources.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-bundle-resources.py
index e9eddb70fa..45b28f438d 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-bundle-resources.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-bundle-resources.py
@@ -15,7 +15,7 @@ import stat
 import sys
 
 if sys.platform in ('darwin'):
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py
index 4146441862..59156e5054 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-copies.py
@@ -15,7 +15,7 @@ import sys
 import time
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py
index 486fbfe2da..568f741034 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-depend-on-bundle.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py
index 553cc9f648..efbfaf0343 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-framework.py
@@ -14,7 +14,7 @@ import os
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
@@ -67,12 +67,12 @@ if sys.platform == 'darwin':
   # Check that no other files get added to the bundle.
   if set(ls(test.built_file_path('Test Framework.framework',
                                  chdir='framework'))) != \
-     set(['Versions/A/Test Framework',
+     {'Versions/A/Test Framework',
           'Versions/A/Resources/Info.plist',
           'Versions/A/Resources/English.lproj/InfoPlist.strings',
           'Test Framework',
           'Versions/A/Libraries/empty.c',  # Written by a gyp action.
-          ]):
+          }:
     test.fail_test()
 
   test.pass_test()
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py
index 2e5168477e..dff0991356 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-infoplist-process.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py
index 3fc7152242..0cc80d9200 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-installname.py
@@ -16,7 +16,7 @@ import subprocess
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
index 48afcd46bc..5c9c17b3f4 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-ldflags-passed-to-libtool.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'],
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py
index 158a930552..19242b040b 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-loadable-module.py
@@ -15,7 +15,7 @@ import struct
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-lto.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-lto.py
index 5171544750..d417135d3f 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-lto.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-lto.py
@@ -44,7 +44,7 @@ if sys.platform == 'darwin':
     elif ': LLVM bit-code ' in o:
       objtype = 'llvm'
     if objtype != t_expected:
-      print 'Expected %s, got %s' % (t_expected, objtype)
+      print('Expected {}, got {}'.format(t_expected, objtype))
       test.fail_test()
 
   ObjType(ObjPath('cfile', 'lto'), 'llvm')
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py
index 43cab77bdf..0289c92e31 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-missing-cfbundlesignature.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
index b802619ba2..571c12523b 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-non-strs-flattened-to-env.py
@@ -14,7 +14,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py
index 892a0c4b06..f223e354a5 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-defaults.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py
index 9cd5d47d28..319338fe8a 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-postbuild-fail.py
@@ -39,7 +39,7 @@ if sys.platform == 'darwin':
                          stderr=subprocess.STDOUT)
   out, err = job.communicate()
   if job.returncode != 0:
-    print out
+    print(out)
     raise Exception('Error %d running xcodebuild' % job.returncode)
   if out.startswith('Xcode 3.'):
     test.pass_test()
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py
index e615d06786..4473ce7351 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-rebuild.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py
index f7d41cd25a..38733d3f77 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sdkroot.py
@@ -16,7 +16,7 @@ import sys
 
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.py
index c34bc546bd..a1280c97fe 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-sourceless-module.py
@@ -13,7 +13,7 @@ import TestGyp
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip-default.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip-default.py
index f73fa1124c..6c4d65bdd8 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip-default.py
@@ -34,14 +34,14 @@ if sys.platform == 'darwin':
     # Filter out mysterious "00 0000   OPT radr://5614542" symbol which
     # is apparently only printed on the bots (older toolchain?).
     # Yes, "radr", not "rdar".
-    o = ''.join(filter(lambda s: 'radr://5614542' not in s, o.splitlines(True)))
+    o = ''.join([s for s in o.splitlines(True) if 'radr://5614542' not in s])
 
     o = o.replace('A', 'T')
     o = re.sub(r'^[a-fA-F0-9]+', 'XXXXXXXX', o, flags=re.MULTILINE)
     assert not proc.returncode
     if o != o_expected:
-      print 'Stripping: Expected symbols """\n%s""", got """\n%s"""' % (
-          o_expected, o)
+      print('Stripping: Expected symbols """\n{}""", got """\n{}"""'.format(
+          o_expected, o))
       test.fail_test()
 
   CheckNsyms(OutPath('libsingle_dylib.dylib'),
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py
index a729521e18..357f48f59a 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-strip.py
@@ -33,7 +33,7 @@ if sys.platform == 'darwin':
     m = r.search(o)
     n = int(m.group(1))
     if n != n_expected:
-      print 'Stripping: Expected %d symbols, got %d' % (n_expected, n)
+      print('Stripping: Expected %d symbols, got %d' % (n_expected, n))
       test.fail_test()
 
   # Starting with Xcode 5.0, clang adds an additional symbols to the compiled
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-swift-library.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-swift-library.py
index dde7a62351..961128a375 100644
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-swift-library.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-swift-library.py
@@ -16,7 +16,7 @@ import sys
 import subprocess
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['xcode'])
@@ -26,7 +26,7 @@ if sys.platform == 'darwin':
     output = subprocess.check_output(['nm', '-j', path])
     idx = output.find(symbol)
     if idx == -1:
-      print 'Swift: Could not find symobl: %s' % symbol
+      print('Swift: Could not find symobl: %s' % symbol)
       test.fail_test()
 
   test_cases = []
diff --git a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py
index 6e7ca2413f..9898c226ee 100755
--- a/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py
+++ b/media/webrtc/trunk/tools/gyp/test/mac/gyptest-xcode-env-order.py
@@ -15,7 +15,7 @@ import subprocess
 import sys
 
 if sys.platform == 'darwin':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
diff --git a/media/webrtc/trunk/tools/gyp/test/make/gyptest-noload.py b/media/webrtc/trunk/tools/gyp/test/make/gyptest-noload.py
index 1f5103315c..9542a5d895 100755
--- a/media/webrtc/trunk/tools/gyp/test/make/gyptest-noload.py
+++ b/media/webrtc/trunk/tools/gyp/test/make/gyptest-noload.py
@@ -10,7 +10,6 @@ optional.
 """
 
 # Python 2.5 needs this for the with statement.
-from __future__ import with_statement
 
 import os
 import TestGyp
diff --git a/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_nm.py b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_nm.py
index f0f1efcf73..578d680bc5 100755
--- a/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_nm.py
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_nm.py
@@ -3,6 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
 with open('RAN_MY_NM', 'w') as f:
   f.write('RAN_MY_NM')
diff --git a/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_readelf.py b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_readelf.py
index 40e303cd76..6ec7c9ea22 100755
--- a/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_readelf.py
+++ b/media/webrtc/trunk/tools/gyp/test/make_global_settings/full-toolchain/my_readelf.py
@@ -3,6 +3,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 import sys
-print sys.argv
+print(sys.argv)
 with open('RAN_MY_READELF', 'w') as f:
   f.write('RAN_MY_READELF')
diff --git a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py
index 90d3c92e4c..1be553726a 100644
--- a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py
+++ b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions-unsorted.py
@@ -9,10 +9,11 @@ Make sure lots of actions in the same target don't cause exceeding command
 line length.
 """
 
+from __future__ import print_function
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 import TestGyp
diff --git a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py
index f2e719bb70..e0d75c983b 100644
--- a/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py
+++ b/media/webrtc/trunk/tools/gyp/test/many-actions/gyptest-many-actions.py
@@ -9,10 +9,11 @@ Make sure lots of actions in the same target don't cause exceeding command
 line length.
 """
 
+from __future__ import print_function
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py b/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
index d5603744db..b01f3c9311 100644
--- a/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/config_attrs/gyptest-config_attrs.py
@@ -16,7 +16,7 @@ import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stderr.py b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stderr.py
index f4860624f3..fc1b04331c 100644
--- a/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stderr.py
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stderr.py
@@ -4,4 +4,4 @@
 # found in the LICENSE file.
 
 import sys
-print >>sys.stderr, "This will go to stderr"
+print("This will go to stderr", file=sys.stderr)
diff --git a/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stdout.py b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stdout.py
index 2b58d2a374..8881d44d64 100644
--- a/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stdout.py
+++ b/media/webrtc/trunk/tools/gyp/test/msvs/rules_stdout_stderr/rule_stdout.py
@@ -3,4 +3,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-print "This will go to stdout"
+#!/usr/bin/env python
+# Copyright (c) 2015 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+print("This will go to stdout")
diff --git a/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py b/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
index cb59d7e3c1..16556ef9a8 100755
--- a/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/action_dependencies/gyptest-action-dependencies.py
@@ -13,7 +13,7 @@ import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py b/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
index 1b8e812eb2..b8277509de 100755
--- a/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
+++ b/media/webrtc/trunk/tools/gyp/test/ninja/solibs_avoid_relinking/gyptest-solibs-avoid-relinking.py
@@ -24,7 +24,7 @@ test = TestGyp.TestGyp(formats=['ninja'])
 
 if not os.environ.get('ProgramFiles(x86)'):
   # TODO(scottmg)
-  print 'Skipping test on x86, http://crbug.com/365833'
+  print('Skipping test on x86, http://crbug.com/365833')
   test.pass_test()
 
 test.run_gyp('solibs_avoid_relinking.gyp')
diff --git a/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py b/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py
index 9b8949b32c..bed1f823f1 100755
--- a/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules-dirname/gyptest-dirname.py
@@ -8,12 +8,13 @@
 Verifies simple rules when using an explicit build target of 'all'.
 """
 
+from __future__ import print_function
 import TestGyp
 import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py b/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py
index c1825e0c13..b2e0826ef4 100755
--- a/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules-variables/gyptest-rules-variables.py
@@ -8,10 +8,11 @@
 Verifies rules related variables are expanded.
 """
 
+from __future__ import print_function
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py
index e6e637ebbf..4aa925d501 100755
--- a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-all.py
@@ -11,7 +11,7 @@ Verifies simple rules when using an explicit build target of 'all'.
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py
index 65b79dacd6..29c9ea97e6 100755
--- a/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules/gyptest-default.py
@@ -11,7 +11,7 @@ Verifies simple rules when using an explicit build target of 'all'.
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/rules/src/copy-file.py b/media/webrtc/trunk/tools/gyp/test/rules/src/copy-file.py
index 5a5feae1f2..c95252b975 100755
--- a/media/webrtc/trunk/tools/gyp/test/rules/src/copy-file.py
+++ b/media/webrtc/trunk/tools/gyp/test/rules/src/copy-file.py
@@ -5,7 +5,7 @@
 # found in the LICENSE file.
 import sys
 
-contents = open(sys.argv[1], 'r').read()
+contents = open(sys.argv[1]).read()
 open(sys.argv[2], 'wb').write(contents)
 
 sys.exit(0)
diff --git a/media/webrtc/trunk/tools/gyp/test/standalone/gyptest-standalone.py b/media/webrtc/trunk/tools/gyp/test/standalone/gyptest-standalone.py
index 87143706ab..a9faef1117 100644
--- a/media/webrtc/trunk/tools/gyp/test/standalone/gyptest-standalone.py
+++ b/media/webrtc/trunk/tools/gyp/test/standalone/gyptest-standalone.py
@@ -26,7 +26,7 @@ for root, dirs, files in os.walk("."):
     file = os.path.join(root, file)
     contents = open(file).read()
     if 'standalone.gyp' in contents:
-      print 'gyp file referenced in generated output: %s' % file
+      print('gyp file referenced in generated output: %s' % file)
       test.fail_test()
 
 
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-ignore-env.py b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-ignore-env.py
index 1cf3308dc4..6d1cdbd0ce 100755
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-ignore-env.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-ignore-env.py
@@ -39,7 +39,7 @@ test.run_gyp('commands.gyp',
 contents = test.read('commands.gypd').replace('\r', '')
 expect = test.read('commands.gypd.golden').replace('\r', '')
 if not test.match(contents, expect):
-  print "Unexpected contents of `commands.gypd'"
+  print("Unexpected contents of `commands.gypd'")
   test.diff(expect, contents, 'commands.gypd ')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-repeated.py b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-repeated.py
index b95fe2d75e..eb76542250 100755
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-repeated.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands-repeated.py
@@ -31,7 +31,7 @@ test.run_gyp('commands-repeated.gyp',
 contents = test.read('commands-repeated.gypd').replace('\r\n', '\n')
 expect = test.read('commands-repeated.gypd.golden').replace('\r\n', '\n')
 if not test.match(contents, expect):
-  print "Unexpected contents of `commands-repeated.gypd'"
+  print("Unexpected contents of `commands-repeated.gypd'")
   test.diff(expect, contents, 'commands-repeated.gypd ')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands.py b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands.py
index ef1af8c525..1b0d256eb0 100755
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/gyptest-commands.py
@@ -32,7 +32,7 @@ test.run_gyp('commands.gyp',
 contents = test.read('commands.gypd').replace('\r', '')
 expect = test.read('commands.gypd.golden').replace('\r', '')
 if not test.match(contents, expect):
-  print "Unexpected contents of `commands.gypd'"
+  print("Unexpected contents of `commands.gypd'")
   test.diff(expect, contents, 'commands.gypd ')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py
index ace9ed6b80..52c99e0c8c 100755
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/repeated_multidir/print_cwd_basename.py
@@ -7,4 +7,4 @@
 import os
 import os.path
 
-print os.path.basename(os.getcwd())
+print(os.path.basename(os.getcwd()))
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/commands/test.py b/media/webrtc/trunk/tools/gyp/test/variables/commands/test.py
index 4d9ca6d1ab..a76c00572a 100644
--- a/media/webrtc/trunk/tools/gyp/test/variables/commands/test.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/commands/test.py
@@ -1 +1 @@
-print "sample\\path\\foo.cpp"
+print("sample\\path\\foo.cpp")
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist-golden.py b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist-golden.py
index 55eaf9db46..7162043390 100644
--- a/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist-golden.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist-golden.py
@@ -36,14 +36,14 @@ contents = test.read('src/filelist.gypd').replace(
     '\r', '').replace('\\\\', '/')
 expect = test.read('filelist.gypd.golden').replace('\r', '')
 if not test.match(contents, expect):
-  print "Unexpected contents of `src/filelist.gypd'"
+  print("Unexpected contents of `src/filelist.gypd'")
   test.diff(expect, contents, 'src/filelist.gypd ')
   test.fail_test()
 
 contents = test.read('src/names.txt')
 expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
 if not test.match(contents, expect):
-  print "Unexpected contents of `src/names.txt'"
+  print("Unexpected contents of `src/names.txt'")
   test.diff(expect, contents, 'src/names.txt ')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py
index 84a6cba5f4..b12084c21c 100755
--- a/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py
+++ b/media/webrtc/trunk/tools/gyp/test/variables/filelist/gyptest-filelist.py
@@ -22,7 +22,7 @@ test.build('filelist2.gyp', 'foo', chdir=CHDIR)
 contents = test.read('src/dummy_foo').replace('\r', '')
 expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
 if not test.match(contents, expect):
-  print "Unexpected contents of `src/dummy_foo'"
+  print("Unexpected contents of `src/dummy_foo'")
   test.diff(expect, contents, 'src/dummy_foo')
   test.fail_test()
 
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py
index 78a924aba3..ac6af8dafc 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-enable-enhanced-instruction-set.py
@@ -8,13 +8,14 @@
 Test VCCLCompilerTool EnableEnhancedInstructionSet setting.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp()
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-function-level-linking.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-function-level-linking.py
index 17c29e235f..56e1027e49 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-function-level-linking.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-cl-function-level-linking.py
@@ -8,6 +8,7 @@
 Make sure function-level linking setting is extracted properly.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import sys
@@ -22,10 +23,10 @@ if sys.platform == 'win32':
   def CheckForSectionString(binary, search_for, should_exist):
     output = test.run_dumpbin('/headers', binary)
     if should_exist and search_for not in output:
-      print 'Did not find "%s" in %s' % (search_for, binary)
+      print('Did not find "%s" in %s' % (search_for, binary))
       test.fail_test()
     elif not should_exist and search_for in output:
-      print 'Found "%s" in %s (and shouldn\'t have)' % (search_for, binary)
+      print('Found "%s" in %s (and shouldn\'t have)' % (search_for, binary))
       test.fail_test()
 
   def Object(proj, obj):
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py
index bd93ac5e92..871f35b1a4 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-command-quote.py
@@ -12,12 +12,13 @@ application in the path. Specifically, this means not quoting something like
 than calling "x.bat".
 """
 
+from __future__ import print_function
 import TestGyp
 
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-defrelink.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-defrelink.py
index cec0ea1870..733a5aa797 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-defrelink.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-defrelink.py
@@ -8,12 +8,13 @@
 Make sure a relink is performed when a .def file is touched.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-uac.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-uac.py
index 131e07ec1f..731e50a135 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-uac.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-uac.py
@@ -68,8 +68,8 @@ if sys.platform == 'win32':
   test.fail_test(len(execution_level) != 1)
   execution_level = execution_level[0].attributes
   test.fail_test(not (
-      execution_level.has_key('level') and
-      execution_level.has_key('uiAccess') and
+      'level' in execution_level and
+      'uiAccess' in execution_level and
       execution_level['level'].nodeValue == 'asInvoker' and
       execution_level['uiAccess'].nodeValue == 'false'))
 
@@ -87,8 +87,8 @@ if sys.platform == 'win32':
   test.fail_test(len(execution_level) != 1)
   execution_level = execution_level[0].attributes
   test.fail_test(not (
-      execution_level.has_key('level') and
-      execution_level.has_key('uiAccess') and
+      'level' in execution_level and
+      'uiAccess' in execution_level and
       execution_level['level'].nodeValue == 'requireAdministrator' and
       execution_level['uiAccess'].nodeValue == 'true'))
 
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-app-revision.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-app-revision.py
index e5c5a71335..31195c2cf3 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-app-revision.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-app-revision.py
@@ -8,6 +8,7 @@
 Make sure msvs_application_type_revision works correctly.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
@@ -16,7 +17,7 @@ import struct
 
 CHDIR = 'winrt-app-type-revision'
 
-print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+print('This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466')
 sys.exit(0)
 
 if (sys.platform == 'win32' and
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-target-platform-version.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-target-platform-version.py
index cd9244ed01..da29716d59 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-target-platform-version.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt-target-platform-version.py
@@ -8,6 +8,7 @@
 Make sure msvs_target_platform_version works correctly.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
@@ -16,7 +17,7 @@ import struct
 
 CHDIR = 'winrt-target-platform-version'
 
-print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+print('This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466')
 sys.exit(0)
 
 if (sys.platform == 'win32' and
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt.py
index 283863ced7..67ccd5453e 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-enable-winrt.py
@@ -8,6 +8,7 @@
 Make sure msvs_enable_winrt works correctly.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
@@ -16,7 +17,7 @@ import struct
 
 CHDIR = 'enable-winrt'
 
-print 'This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466'
+print('This test is not currently working on the bots: https://code.google.com/p/gyp/issues/detail?id=466')
 sys.exit(0)
 
 if (sys.platform == 'win32' and
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-pdb.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-pdb.py
index 4604745d14..f42d9d8b11 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-pdb.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-large-pdb.py
@@ -8,13 +8,14 @@
 Make sure msvs_large_pdb works correctly.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import struct
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
 
@@ -37,8 +38,8 @@ def CheckImageAndPdb(test, image_basename, expected_page_size,
   pdb_file.seek(32, 0)
   page_size = struct.unpack('<I', pdb_file.read(4))[0]
   if page_size != expected_page_size:
-    print "Expected page size of %d, got %d for PDB file `%s'." % (
-        expected_page_size, page_size, pdb_path)
+    print("Expected page size of %d, got %d for PDB file `%s'." % (
+        expected_page_size, page_size, pdb_path))
 
 
 if sys.platform == 'win32':
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ordering.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ordering.py
index a2527fa3b4..9959cc786c 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ordering.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-ordering.py
@@ -8,6 +8,7 @@
 Make sure the link order of object files is the same between msvs and ninja.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import sys
@@ -48,7 +49,7 @@ _main:
 '''
 
   if expected_disasm_basic not in GetDisasm('test_ordering_exe.exe'):
-    print GetDisasm('test_ordering_exe.exe')
+    print(GetDisasm('test_ordering_exe.exe'))
     test.fail_test()
 
   # Similar to above. The VS generator handles subdirectories differently.
@@ -69,7 +70,7 @@ _main:
 '''
 
   if expected_disasm_subdirs not in GetDisasm('test_ordering_subdirs.exe'):
-    print GetDisasm('test_ordering_subdirs.exe')
+    print(GetDisasm('test_ordering_subdirs.exe'))
     test.fail_test()
 
   # Similar, but with directories mixed into folders (crt and main at the same
@@ -95,7 +96,7 @@ _main:
 
   if (expected_disasm_subdirs_mixed not in
       GetDisasm('test_ordering_subdirs_mixed.exe')):
-    print GetDisasm('test_ordering_subdirs_mixed.exe')
+    print(GetDisasm('test_ordering_subdirs_mixed.exe'))
     test.fail_test()
 
   test.pass_test()
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py
index 76b5c3cdb9..5b38306ed2 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-link-restat-importlib.py
@@ -9,6 +9,7 @@ Make sure we don't cause unnecessary builds due to import libs appearing
 to be out of date.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
@@ -20,7 +21,7 @@ if sys.platform == 'win32':
 
   if not os.environ.get('ProgramFiles(x86)'):
     # TODO(scottmg)
-    print 'Skipping test on x86, http://crbug.com/365833'
+    print('Skipping test on x86, http://crbug.com/365833')
     test.pass_test()
 
   CHDIR = 'importlib'
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetfilename.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetfilename.py
index be4b637e9c..c42c5030ce 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetfilename.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-macro-targetfilename.py
@@ -8,13 +8,14 @@
 Make sure macro expansion of $(TargetFileName) is handled.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import os
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
diff --git a/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py b/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py
index a6e4d360f6..dcad897300 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/gyptest-rc-build.py
@@ -8,12 +8,13 @@
 Make sure we build and include .rc files.
 """
 
+from __future__ import print_function
 import TestGyp
 
 import sys
 
 if sys.platform == 'win32':
-  print "This test is currently disabled: https://crbug.com/483696."
+  print("This test is currently disabled: https://crbug.com/483696.")
   sys.exit(0)
 
   test = TestGyp.TestGyp(formats=['msvs', 'ninja'])
diff --git a/media/webrtc/trunk/tools/gyp/test/win/vs-macros/as.py b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/as.py
index e0bc3ae6f3..c4b549ac10 100644
--- a/media/webrtc/trunk/tools/gyp/test/win/vs-macros/as.py
+++ b/media/webrtc/trunk/tools/gyp/test/win/vs-macros/as.py
@@ -4,6 +4,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from __future__ import print_function
 from optparse import OptionParser
 
 parser = OptionParser()
@@ -13,6 +14,6 @@ parser.add_option('-p', dest='path')
 (options, args) = parser.parse_args()
 
 f = open(options.output, 'w')
-print >>f, 'options', options
-print >>f, 'args', args
+print('options', options, file=f)
+print('args', args, file=f)
 f.close()
diff --git a/media/webrtc/trunk/tools/gyp/tools/graphviz.py b/media/webrtc/trunk/tools/gyp/tools/graphviz.py
index 326ae221cf..2f9a0fb171 100755
--- a/media/webrtc/trunk/tools/gyp/tools/graphviz.py
+++ b/media/webrtc/trunk/tools/gyp/tools/graphviz.py
@@ -50,9 +50,9 @@ def WriteGraph(edges):
     build_file, target_name, toolset = ParseTarget(src)
     files[build_file].append(src)
 
-  print 'digraph D {'
-  print '  fontsize=8'  # Used by subgraphs.
-  print '  node [fontsize=8]'
+  print('digraph D {')
+  print('  fontsize=8')  # Used by subgraphs.
+  print('  node [fontsize=8]')
 
   # Output nodes by file.  We must first write out each node within
   # its file grouping before writing out any edges that may refer
@@ -63,31 +63,31 @@ def WriteGraph(edges):
       # the display by making it a box without an internal node.
       target = targets[0]
       build_file, target_name, toolset = ParseTarget(target)
-      print '  "%s" [shape=box, label="%s\\n%s"]' % (target, filename,
-                                                     target_name)
+      print('  "{}" [shape=box, label="{}\\n{}"]'.format(target, filename,
+                                                     target_name))
     else:
       # Group multiple nodes together in a subgraph.
-      print '  subgraph "cluster_%s" {' % filename
-      print '    label = "%s"' % filename
+      print('  subgraph "cluster_%s" {' % filename)
+      print('    label = "%s"' % filename)
       for target in targets:
         build_file, target_name, toolset = ParseTarget(target)
-        print '    "%s" [label="%s"]' % (target, target_name)
-      print '  }'
+        print('    "{}" [label="{}"]'.format(target, target_name))
+      print('  }')
 
   # Now that we've placed all the nodes within subgraphs, output all
   # the edges between nodes.
   for src, dsts in edges.items():
     for dst in dsts:
-      print '  "%s" -> "%s"' % (src, dst)
+      print('  "{}" -> "{}"'.format(src, dst))
 
-  print '}'
+  print('}')
 
 
 def main():
   if len(sys.argv) < 2:
-    print >>sys.stderr, __doc__
-    print >>sys.stderr
-    print >>sys.stderr, 'usage: %s target1 target2...' % (sys.argv[0])
+    print(__doc__, file=sys.stderr)
+    print(file=sys.stderr)
+    print('usage: %s target1 target2...' % (sys.argv[0]), file=sys.stderr)
     return 1
 
   edges = LoadEdges('dump.json', sys.argv[1:])
diff --git a/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py b/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py
index d5736bbd4a..b9eaa2c55d 100755
--- a/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py
+++ b/media/webrtc/trunk/tools/gyp/tools/pretty_gyp.py
@@ -32,7 +32,7 @@ def mask_comments(input):
 
 
 def quote_replace(matchobj):
-  return "%s%s%s%s" % (matchobj.group(1),
+  return "{}{}{}{}".format(matchobj.group(1),
                        matchobj.group(2),
                        'x'*len(matchobj.group(3)),
                        matchobj.group(2))
@@ -125,15 +125,15 @@ def prettyprint_input(lines):
         (brace_diff, after) = count_braces(line)
       if brace_diff != 0:
         if after:
-          print " " * (basic_offset * indent) + line
+          print(" " * (basic_offset * indent) + line)
           indent += brace_diff
         else:
           indent += brace_diff
-          print " " * (basic_offset * indent) + line
+          print(" " * (basic_offset * indent) + line)
       else:
-        print " " * (basic_offset * indent) + line
+        print(" " * (basic_offset * indent) + line)
     else:
-      print ""
+      print("")
     last_line = line
 
 
diff --git a/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py b/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py
index ca8cf4ad3f..b1f5bda357 100755
--- a/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py
+++ b/media/webrtc/trunk/tools/gyp/tools/pretty_sln.py
@@ -26,7 +26,7 @@ def BuildProject(project, built, projects, deps):
   for dep in deps[project]:
     if dep not in built:
       BuildProject(dep, built, projects, deps)
-  print project
+  print(project)
   built.append(project)
 
 def ParseSolution(solution_file):
@@ -100,44 +100,44 @@ def ParseSolution(solution_file):
   return (projects, dependencies)
 
 def PrintDependencies(projects, deps):
-  print "---------------------------------------"
-  print "Dependencies for all projects"
-  print "---------------------------------------"
-  print "--                                   --"
+  print("---------------------------------------")
+  print("Dependencies for all projects")
+  print("---------------------------------------")
+  print("--                                   --")
 
   for (project, dep_list) in sorted(deps.items()):
-    print "Project : %s" % project
-    print "Path : %s" % projects[project][0]
+    print("Project : %s" % project)
+    print("Path : %s" % projects[project][0])
     if dep_list:
       for dep in dep_list:
-        print "  - %s" % dep
-    print ""
+        print("  - %s" % dep)
+    print("")
 
-  print "--                                   --"
+  print("--                                   --")
 
 def PrintBuildOrder(projects, deps):
-  print "---------------------------------------"
-  print "Build order                            "
-  print "---------------------------------------"
-  print "--                                   --"
+  print("---------------------------------------")
+  print("Build order                            ")
+  print("---------------------------------------")
+  print("--                                   --")
 
   built = []
   for (project, _) in sorted(deps.items()):
     if project not in built:
       BuildProject(project, built, projects, deps)
 
-  print "--                                   --"
+  print("--                                   --")
 
 def PrintVCProj(projects):
 
   for project in projects:
-    print "-------------------------------------"
-    print "-------------------------------------"
-    print project
-    print project
-    print project
-    print "-------------------------------------"
-    print "-------------------------------------"
+    print("-------------------------------------")
+    print("-------------------------------------")
+    print(project)
+    print(project)
+    print(project)
+    print("-------------------------------------")
+    print("-------------------------------------")
 
     project_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[1]),
                                                 projects[project][2]))
@@ -153,7 +153,7 @@ def PrintVCProj(projects):
 def main():
   # check if we have exactly 1 parameter.
   if len(sys.argv) < 2:
-    print 'Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0]
+    print('Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0])
     return 1
 
   (projects, deps) = ParseSolution(sys.argv[1])
diff --git a/media/webrtc/trunk/tools/gyp/tools/pretty_vcproj.py b/media/webrtc/trunk/tools/gyp/tools/pretty_vcproj.py
index 6099bd7cc4..1326b9c4b8 100755
--- a/media/webrtc/trunk/tools/gyp/tools/pretty_vcproj.py
+++ b/media/webrtc/trunk/tools/gyp/tools/pretty_vcproj.py
@@ -24,13 +24,13 @@ REPLACEMENTS = dict()
 ARGUMENTS = None
 
 
-class CmpTuple(object):
+class CmpTuple:
   """Compare function between 2 tuple."""
   def __call__(self, x, y):
     return cmp(x[0], y[0])
 
 
-class CmpNode(object):
+class CmpNode:
   """Compare function between 2 xml nodes."""
 
   def __call__(self, x, y):
@@ -61,7 +61,7 @@ class CmpNode(object):
 def PrettyPrintNode(node, indent=0):
   if node.nodeType == Node.TEXT_NODE:
     if node.data.strip():
-      print '%s%s' % (' '*indent, node.data.strip())
+      print('{}{}'.format(' '*indent, node.data.strip()))
     return
 
   if node.childNodes:
@@ -73,23 +73,23 @@ def PrettyPrintNode(node, indent=0):
 
   # Print the main tag
   if attr_count == 0:
-    print '%s<%s>' % (' '*indent, node.nodeName)
+    print('{}<{}>'.format(' '*indent, node.nodeName))
   else:
-    print '%s<%s' % (' '*indent, node.nodeName)
+    print('{}<{}'.format(' '*indent, node.nodeName))
 
     all_attributes = []
     for (name, value) in node.attributes.items():
       all_attributes.append((name, value))
       all_attributes.sort(CmpTuple())
     for (name, value) in all_attributes:
-      print '%s  %s="%s"' % (' '*indent, name, value)
-    print '%s>' % (' '*indent)
+      print('{}  {}="{}"'.format(' '*indent, name, value))
+    print('%s>' % (' '*indent))
   if node.nodeValue:
-    print '%s  %s' % (' '*indent, node.nodeValue)
+    print('{}  {}'.format(' '*indent, node.nodeValue))
 
   for sub_node in node.childNodes:
     PrettyPrintNode(sub_node, indent=indent+2)
-  print '%s</%s>' % (' '*indent, node.nodeName)
+  print('{}</{}>'.format(' '*indent, node.nodeName))
 
 
 def FlattenFilter(node):
@@ -283,7 +283,7 @@ def main(argv):
 
   # check if we have exactly 1 parameter.
   if len(argv) < 2:
-    print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
+    print('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
            '[key2=value2]' % argv[0])
     return 1
 
diff --git a/media/webrtc/trunk/webrtc/PRESUBMIT.py b/media/webrtc/trunk/webrtc/PRESUBMIT.py
index 4132c16874..825fc8e0be 100644
--- a/media/webrtc/trunk/webrtc/PRESUBMIT.py
+++ b/media/webrtc/trunk/webrtc/PRESUBMIT.py
@@ -10,7 +10,7 @@ def _LicenseHeader(input_api):
   """Returns the license header regexp."""
   # Accept any year number from 2003 to the current year
   current_year = int(input_api.time.strftime('%Y'))
-  allowed_years = (str(s) for s in reversed(xrange(2003, current_year + 1)))
+  allowed_years = (str(s) for s in reversed(range(2003, current_year + 1)))
   years_re = '(' + '|'.join(allowed_years) + ')'
   license_header = (
       r'.*? Copyright( \(c\))? %(year)s The WebRTC [Pp]roject [Aa]uthors\. '
diff --git a/media/webrtc/trunk/webrtc/build/extra_gitignore.py b/media/webrtc/trunk/webrtc/build/extra_gitignore.py
index f8496686bb..536b83b1a0 100755
--- a/media/webrtc/trunk/webrtc/build/extra_gitignore.py
+++ b/media/webrtc/trunk/webrtc/build/extra_gitignore.py
@@ -28,7 +28,7 @@ def main(argv):
 
   modify_string = MODIFY_STRING % argv[0]
   gitignore_file = os.path.dirname(argv[0]) + '/../../.gitignore'
-  lines = open(gitignore_file, 'r').readlines()
+  lines = open(gitignore_file).readlines()
   for i, line in enumerate(lines):
     # Look for modify_string in the file to ensure we don't append the extra
     # patterns more than once.
@@ -39,7 +39,7 @@ def main(argv):
 
   f = open(gitignore_file, 'w')
   f.write(''.join(lines))
-  f.write(open(argv[1], 'r').read())
+  f.write(open(argv[1]).read())
   f.close()
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/webrtc/build/gyp_webrtc.py b/media/webrtc/trunk/webrtc/build/gyp_webrtc.py
index 87d8a57ddf..4335ccfd4d 100644
--- a/media/webrtc/trunk/webrtc/build/gyp_webrtc.py
+++ b/media/webrtc/trunk/webrtc/build/gyp_webrtc.py
@@ -21,4 +21,4 @@
 import os
 
 path = os.path.abspath(os.path.split(__file__)[0])
-execfile(os.path.join(path, 'gyp_webrtc'))
+exec(compile(open(os.path.join(path, 'gyp_webrtc'), "rb").read(), os.path.join(path, 'gyp_webrtc'), 'exec'))
diff --git a/media/webrtc/trunk/webrtc/build/merge_libs.py b/media/webrtc/trunk/webrtc/build/merge_libs.py
index 84904d61ce..4cd54f84d3 100644
--- a/media/webrtc/trunk/webrtc/build/merge_libs.py
+++ b/media/webrtc/trunk/webrtc/build/merge_libs.py
@@ -79,7 +79,7 @@ def main(argv):
                     ' -exec', cmd, output_lib, '{} +'])
   else:
     cmd = ' '.join([cmd + output_lib] + FindFiles(search_path, pattern))
-  print cmd
+  print(cmd)
   subprocess.check_call(cmd, shell=True)
   return 0
 
diff --git a/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_decoder.py b/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_decoder.py
index b7b7ddd4a6..e85fcd66e3 100755
--- a/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_decoder.py
+++ b/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_decoder.py
@@ -48,15 +48,15 @@ def convert_yuv_to_png_files(yuv_file_name, yuv_frame_width, yuv_frame_height,
              % yuv_file_name, '-f', 'image2', '-vcodec', 'png',
              '%s' % output_files_pattern]
   try:
-    print 'Converting YUV file to PNG images (may take a while)...'
-    print ' '.join(command)
+    print('Converting YUV file to PNG images (may take a while)...')
+    print(' '.join(command))
     helper_functions.run_shell_command(
         command, fail_msg='Error during YUV to PNG conversion')
-  except helper_functions.HelperError, err:
-    print 'Error executing command: %s. Error: %s' % (command, err)
+  except helper_functions.HelperError as err:
+    print('Error executing command: {}. Error: {}'.format(command, err))
     return False
   except OSError:
-    print ('Did not find %s. Have you installed it?' % ffmpeg_path)
+    print('Did not find %s. Have you installed it?' % ffmpeg_path)
     return False
   return True
 
@@ -82,7 +82,7 @@ def decode_frames(input_directory, zxing_path):
   """
   if not zxing_path:
     zxing_path = 'zxing.exe' if sys.platform == 'win32' else 'zxing'
-  print 'Decoding barcodes from PNG files with %s...' % zxing_path
+  print('Decoding barcodes from PNG files with %s...' % zxing_path)
   return helper_functions.perform_action_on_all_files(
       directory=input_directory, file_pattern='frame_',
       file_extension='png', start_number=1, action=_decode_barcode_in_file,
@@ -106,12 +106,12 @@ def _decode_barcode_in_file(file_name, command_line_decoder):
     text_file = open('%s.txt' % file_name[:-4], 'w')
     text_file.write(out)
     text_file.close()
-  except helper_functions.HelperError, err:
-    print 'Barcode in %s cannot be decoded.' % file_name
-    print err
+  except helper_functions.HelperError as err:
+    print('Barcode in %s cannot be decoded.' % file_name)
+    print(err)
     return False
   except OSError:
-    print ('Did not find %s. Have you installed it?' % command_line_decoder)
+    print('Did not find %s. Have you installed it?' % command_line_decoder)
     return False
   return True
 
@@ -127,7 +127,7 @@ def _generate_stats_file(stats_file_name, input_directory='.'):
   file_prefix = os.path.join(input_directory, 'frame_')
   stats_file = open(stats_file_name, 'w')
 
-  print 'Generating stats file: %s' % stats_file_name
+  print('Generating stats file: %s' % stats_file_name)
   for i in range(1, _count_frames_in(input_directory=input_directory) + 1):
     frame_number = helper_functions.zero_pad(i)
     barcode_file_name = file_prefix + frame_number + '.txt'
@@ -160,7 +160,7 @@ def _read_barcode_from_text_file(barcode_file_name):
   Return:
     (string): The decoded barcode.
   """
-  barcode_file = open(barcode_file_name, 'r')
+  barcode_file = open(barcode_file_name)
   barcode = barcode_file.read()
   barcode_file.close()
   return barcode
@@ -180,8 +180,8 @@ def _check_barcode(barcode):
   if len(barcode) != 12:
     return False
 
-  r1 = range(0, 11, 2)  # Odd digits
-  r2 = range(1, 10, 2)  # Even digits except last
+  r1 = list(range(0, 11, 2))  # Odd digits
+  r2 = list(range(1, 10, 2))  # Even digits except last
   dsum = 0
   # Sum all the even digits
   for i in r1:
@@ -272,19 +272,19 @@ def _main():
                                   options.yuv_frame_height,
                                   output_directory=options.png_working_dir,
                                   ffmpeg_path=options.ffmpeg_path):
-    print 'An error occurred converting from YUV to PNG frames.'
+    print('An error occurred converting from YUV to PNG frames.')
     return -1
 
   # Decode the barcodes from the PNG frames.
   if not decode_frames(input_directory=options.png_working_dir,
                        zxing_path=options.zxing_path):
-    print 'An error occurred decoding barcodes from PNG frames.'
+    print('An error occurred decoding barcodes from PNG frames.')
     return -2
 
   # Generate statistics file.
   _generate_stats_file(options.stats_file,
                        input_directory=options.png_working_dir)
-  print 'Completed barcode decoding.'
+  print('Completed barcode decoding.')
   return 0
 
 if __name__ == '__main__':
diff --git a/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_encoder.py b/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_encoder.py
index 3a8f35499d..937b64fc27 100755
--- a/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_encoder.py
+++ b/media/webrtc/trunk/webrtc/tools/barcode_tools/barcode_encoder.py
@@ -59,7 +59,7 @@ def generate_upca_barcodes(number_of_barcodes, barcode_width, barcode_height,
       helper_functions.run_shell_command(
           command, fail_msg=('Error during barcode %s generation' % content))
     except helper_functions.HelperError as err:
-      print >> sys.stderr, err
+      print(err, file=sys.stderr)
       errors = True
   return not errors
 
@@ -111,7 +111,7 @@ def _convert_to_yuv_and_delete(output_directory, file_name, pattern):
                            file_name))
     os.remove(file_name)
   except helper_functions.HelperError as err:
-    print >> sys.stderr, err
+    print(err, file=sys.stderr)
     return False
   return True
 
@@ -154,7 +154,7 @@ def _add_to_file_and_delete(output_file, file_name):
   try:
     os.remove(file_name)
   except OSError as e:
-    print >> sys.stderr, 'Error deleting file %s.\nError: %s' % (file_name, e)
+    print('Error deleting file {}.\nError: {}'.format(file_name, e), file=sys.stderr)
     return False
   return True
 
diff --git a/media/webrtc/trunk/webrtc/tools/barcode_tools/build_zxing.py b/media/webrtc/trunk/webrtc/tools/barcode_tools/build_zxing.py
index 466bd50fd9..35080879b1 100755
--- a/media/webrtc/trunk/webrtc/tools/barcode_tools/build_zxing.py
+++ b/media/webrtc/trunk/webrtc/tools/barcode_tools/build_zxing.py
@@ -25,11 +25,11 @@ def run_ant_build_command(path_to_ant_build_file):
     process = subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr)
     process.wait()
     if process.returncode != 0:
-      print >> sys.stderr, 'Failed to execute: %s' % ' '.join(cmd)
+      print('Failed to execute: %s' % ' '.join(cmd), file=sys.stderr)
     return process.returncode
   except subprocess.CalledProcessError as e:
-    print >> sys.stderr, 'Failed to execute: %s.\nCause: %s' % (' '.join(cmd),
-                                                                e)
+    print('Failed to execute: {}.\nCause: {}'.format(' '.join(cmd),
+                                                                e), file=sys.stderr)
     return -1
 
 def _main():
diff --git a/media/webrtc/trunk/webrtc/tools/barcode_tools/helper_functions.py b/media/webrtc/trunk/webrtc/tools/barcode_tools/helper_functions.py
index bb0b167334..75702fb375 100644
--- a/media/webrtc/trunk/webrtc/tools/barcode_tools/helper_functions.py
+++ b/media/webrtc/trunk/webrtc/tools/barcode_tools/helper_functions.py
@@ -52,7 +52,7 @@ def run_shell_command(cmd_list, fail_msg=None):
   output, error = process.communicate()
   if process.returncode != 0:
     if fail_msg:
-      print >> sys.stderr, fail_msg
+      print(fail_msg, file=sys.stderr)
     raise HelperError('Failed to run %s: command returned %d and printed '
                       '%s and %s' % (' '.join(cmd_list), process.returncode,
                                      output, error))
diff --git a/media/webrtc/trunk/webrtc/tools/compare_videos.py b/media/webrtc/trunk/webrtc/tools/compare_videos.py
index f6275a67d3..b5167cdc03 100755
--- a/media/webrtc/trunk/webrtc/tools/compare_videos.py
+++ b/media/webrtc/trunk/webrtc/tools/compare_videos.py
@@ -99,7 +99,7 @@ def main():
 
   # On Windows, sometimes the inherited stdin handle from the parent process
   # fails. Work around this by passing null to stdin to the subprocesses.
-  null_filehandle = open(os.devnull, 'r')
+  null_filehandle = open(os.devnull)
 
   # Run barcode decoder on the test video to identify frame numbers.
   png_working_directory = tempfile.mkdtemp()
@@ -122,7 +122,7 @@ def main():
 
   shutil.rmtree(png_working_directory)
   if barcode_decoder.returncode != 0:
-    print 'Failed to run barcode decoder script.'
+    print('Failed to run barcode decoder script.')
     return 1
 
   # Run frame analyzer to compare the videos and print output.
@@ -139,7 +139,7 @@ def main():
                                     stdout=sys.stdout, stderr=sys.stderr)
   frame_analyzer.wait()
   if frame_analyzer.returncode != 0:
-    print 'Failed to run frame analyzer.'
+    print('Failed to run frame analyzer.')
     return 1
 
   return 0
diff --git a/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/perf/perf_utils.py b/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/perf/perf_utils.py
index 77eda1e7a3..82b4f0c7f2 100644
--- a/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/perf/perf_utils.py
+++ b/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/perf/perf_utils.py
@@ -25,7 +25,7 @@ def PrintPerfResult(graph_name, series_name, data_point, units,
                        this test on the waterfall page, not the stdio page).
   """
   waterfall_indicator = ['', '*'][show_on_waterfall]
-  print '%sRESULT %s: %s= %s %s' % (
+  print('{}RESULT {}: {}= {} {}'.format(
       waterfall_indicator, graph_name, series_name,
-      str(data_point).replace(' ', ''), units)
+      str(data_point).replace(' ', ''), units))
   sys.stdout.flush()
\ No newline at end of file
diff --git a/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/run_audio_test.py b/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/run_audio_test.py
index 51caa42cd9..52f42cf943 100755
--- a/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/run_audio_test.py
+++ b/media/webrtc/trunk/webrtc/tools/e2e_quality/audio/run_audio_test.py
@@ -52,7 +52,7 @@ def main(argv):
 
   # Get the initial default capture device, to restore later.
   command = ['pacmd', 'list-sources']
-  print ' '.join(command)
+  print(' '.join(command))
   proc = subprocess.Popen(command, stdout=subprocess.PIPE)
   output = proc.communicate()[0]
   if proc.returncode != 0:
@@ -67,14 +67,14 @@ def main(argv):
   # We pass the render device for VoiceEngine to select because (for unknown
   # reasons) the virtual device is sometimes not used when the default.
   command = ['pacmd', 'set-default-source', options.play_sink + '.monitor']
-  print ' '.join(command)
+  print(' '.join(command))
   retcode = subprocess.call(command, stdout=subprocess.PIPE)
   if retcode != 0:
     return retcode
 
   command = [options.harness, '--render=' + options.rec_sink,
       '--codec=' + options.codec, '--rate=' + options.rate]
-  print ' '.join(command)
+  print(' '.join(command))
   voe_proc = subprocess.Popen(command)
 
   # If recording starts before there is data available, pacat sometimes
@@ -87,12 +87,12 @@ def main(argv):
       '--channels=' + options.channels, '--raw']
   command = (['pacat', '-p', '-d', options.play_sink] + format_args +
       [options.input])
-  print ' '.join(command)
+  print(' '.join(command))
   play_proc = subprocess.Popen(command)
 
   command = (['pacat', '-r', '-d', options.rec_sink + '.monitor'] +
       format_args + [options.output])
-  print ' '.join(command)
+  print(' '.join(command))
   record_proc = subprocess.Popen(command)
 
   retcode = play_proc.wait()
@@ -104,14 +104,14 @@ def main(argv):
 
   # Restore the initial default capture device.
   command = ['pacmd', 'set-default-source', default_source]
-  print ' '.join(command)
+  print(' '.join(command))
   retcode = subprocess.call(command, stdout=subprocess.PIPE)
   if retcode != 0:
     return retcode
 
   if options.compare and options.regexp:
     command = shlex.split(options.compare) + [options.input, options.output]
-    print ' '.join(command)
+    print(' '.join(command))
     proc = subprocess.Popen(command, stdout=subprocess.PIPE)
     output = proc.communicate()[0]
     if proc.returncode != 0:
diff --git a/netwerk/dns/prepare_tlds.py b/netwerk/dns/prepare_tlds.py
index a97b20948c..4e05530e9c 100644
--- a/netwerk/dns/prepare_tlds.py
+++ b/netwerk/dns/prepare_tlds.py
@@ -50,7 +50,10 @@ def _normalizeHostname(domain):
   def convertLabel(label):
     if _isASCII(label):
       return label.lower()
-    return encodings.idna.ToASCII(label)
+    result = encodings.idna.ToASCII(label)
+    if isinstance(result, bytes):
+      result = result.decode('ascii')
+    return result
   return ".".join(map(convertLabel, domain.split(".")))
 
 def _isASCII(s):
diff --git a/nsprpub/automation/release/nspr-release-helper.py b/nsprpub/automation/release/nspr-release-helper.py
index f62b80404a..0199fc48e2 100644
--- a/nsprpub/automation/release/nspr-release-helper.py
+++ b/nsprpub/automation/release/nspr-release-helper.py
@@ -4,6 +4,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
+from __future__ import print_function
 import os
 import sys
 import datetime
@@ -17,7 +18,7 @@ f_conf = "configure"
 f_conf_in = "configure.in"
 
 def check_call_noisy(cmd, *args, **kwargs):
-    print("Executing command:", cmd)
+    print(("Executing command:", cmd))
     check_call(cmd, *args, **kwargs)
 
 o = OptionParser(usage="client.py [options] remove_beta | set_beta | print_library_versions | set_version_to_minor_release | set_version_to_patch_release | create_nspr_release_archive")
@@ -30,7 +31,7 @@ except IndexError:
     sys.exit(2)
 
 def exit_with_failure(what):
-    print("failure: ", what)
+    print(("failure: ", what))
     sys.exit(2)
 
 def check_files_exist():
@@ -144,12 +145,12 @@ def create_nspr_release_archive():
     check_call_noisy(["mkdir", "-p", nspr_stagedir])
     check_call_noisy(["hg", "archive", "-r", nsprreltag, "--prefix=nspr-" + nsprrel + "/nspr",
                       "../stage/v" + nsprrel + "/src/" + nspr_tar, "-X", ".hgtags"])
-    print("changing to directory " + nspr_stagedir)
+    print(("changing to directory " + nspr_stagedir))
     os.chdir(nspr_stagedir)
 
     check_call("sha1sum " + nspr_tar + " > SHA1SUMS", shell=True)
     check_call("sha256sum " + nspr_tar + " > SHA256SUMS", shell=True)
-    print("created directory " + nspr_stagedir + " with files:")
+    print(("created directory " + nspr_stagedir + " with files:"))
     check_call_noisy(["ls", "-l"])
 
 if action in ('remove_beta'):
diff --git a/nsprpub/build/win32/pgomerge.py b/nsprpub/build/win32/pgomerge.py
index 313d66870d..cbc9dbe672 100644
--- a/nsprpub/build/win32/pgomerge.py
+++ b/nsprpub/build/win32/pgomerge.py
@@ -8,6 +8,7 @@
 # $PWD/$basename.pgd using pgomgr, then deletes them.
 # No errors if any of these files don't exist.
 
+from __future__ import print_function
 import sys, os, os.path, subprocess
 if not sys.platform == "win32":
     raise Exception("This script was only meant for Windows.")
@@ -39,6 +40,6 @@ def MergePGOFiles(basename, pgddir, pgcdir):
 
 if __name__ == '__main__':
   if len(sys.argv) != 3:
-      print >>sys.stderr, "Usage: pgomerge.py <binary basename> <dist/bin>"
+      print("Usage: pgomerge.py <binary basename> <dist/bin>", file=sys.stderr)
       sys.exit(1)
   MergePGOFiles(sys.argv[1], os.getcwd(), sys.argv[2])
diff --git a/old-configure.in b/old-configure.in
index ad404f2051..5049804f57 100644
--- a/old-configure.in
+++ b/old-configure.in
@@ -3637,7 +3637,7 @@ if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
     _subconfigure_subdir="$1"
     _subconfigure_config_args="$ac_configure_args"
   }
-  tmpscript=`$PYTHON -c 'import os, tempfile; print tempfile.mktemp(prefix="subscript.").replace(os.sep, "/")'` || exit 1
+  tmpscript=`$PYTHON -c 'import os, tempfile; print(tempfile.mktemp(prefix="subscript.").replace(os.sep, "/"))'` || exit 1
   ${TOOLCHAIN_PREFIX}m4 "${srcdir}/build/autoconf/subconfigure.m4" \
      "${srcdir}/build/autoconf/altoptions.m4" \
      "${srcdir}/${MOZ_BUILD_APP}/configure.in" > $tmpscript
diff --git a/other-licenses/ply/ply/lex.py b/other-licenses/ply/ply/lex.py
index 267ec100fc..6885ed6736 100644
--- a/other-licenses/ply/ply/lex.py
+++ b/other-licenses/ply/ply/lex.py
@@ -39,7 +39,7 @@ import re, sys, types, copy, os
 # This tuple contains known string types
 try:
     # Python 2.6
-    StringTypes = (types.StringType, types.UnicodeType)
+    StringTypes = (bytes, str)
 except AttributeError:
     # Python 3.0
     StringTypes = (str, bytes)
@@ -49,7 +49,7 @@ except AttributeError:
 
 if sys.version_info[0] < 3:
     def func_code(f):
-        return f.func_code
+        return f.__code__
 else:
     def func_code(f):
         return f.__code__
@@ -177,7 +177,7 @@ class Lexer:
         tf.write("# %s.py. This file automatically created by PLY (version %s). Don't edit!\n" % (tabfile,__version__))
         tf.write("_tabversion   = %s\n" % repr(__version__))
         tf.write("_lextokens    = %s\n" % repr(self.lextokens))
-        tf.write("_lexreflags   = %s\n" % repr(self.lexreflags))
+        tf.write("_lexreflags   = %d\n" % int(self.lexreflags))
         tf.write("_lexliterals  = %s\n" % repr(self.lexliterals))
         tf.write("_lexstateinfo = %s\n" % repr(self.lexstateinfo))
 
@@ -505,6 +505,8 @@ def _form_master_re(relist,reflags,ldict,toknames):
     except Exception:
         m = int(len(relist)/2)
         if m == 0: m = 1
+        if m >= len(relist):
+            raise
         llist, lre, lnames = _form_master_re(relist[:m],reflags,ldict,toknames)
         rlist, rre, rnames = _form_master_re(relist[m:],reflags,ldict,toknames)
         return llist+rlist, lre+rre, lnames+rnames
diff --git a/other-licenses/ply/ply/yacc.py b/other-licenses/ply/ply/yacc.py
index e9f5c65755..a7038f8ed6 100644
--- a/other-licenses/ply/ply/yacc.py
+++ b/other-licenses/ply/ply/yacc.py
@@ -89,21 +89,21 @@ import re, types, sys, os.path
 # Compatibility function for python 2.6/3.0
 if sys.version_info[0] < 3:
     def func_code(f):
-        return f.func_code
+        return f.__code__
 else:
     def func_code(f):
         return f.__code__
 
 # Compatibility
 try:
-    MAXINT = sys.maxint
+    MAXINT = sys.maxsize
 except AttributeError:
     MAXINT = sys.maxsize
 
 # Python 2.x/3.0 compatibility.
 def load_ply_lex():
     if sys.version_info[0] < 3:
-        import lex
+        from . import lex
     else:
         import ply.lex as lex
     return lex
@@ -1844,7 +1844,7 @@ class LRTable(object):
 
     def read_pickle(self,filename):
         try:
-            import cPickle as pickle
+            import six.moves.cPickle as pickle
         except ImportError:
             import pickle
 
@@ -2665,7 +2665,7 @@ del _lr_goto_items
 
     def pickle_table(self,filename,signature=""):
         try:
-            import cPickle as pickle
+            import six.moves.cPickle as pickle
         except ImportError:
             import pickle
         outf = open(filename,"wb")
diff --git a/parser/html/java/htmlparser/generate-encoding-data.py b/parser/html/java/htmlparser/generate-encoding-data.py
index 69b2fdc309..8466dd2e05 100644
--- a/parser/html/java/htmlparser/generate-encoding-data.py
+++ b/parser/html/java/htmlparser/generate-encoding-data.py
@@ -608,16 +608,16 @@ final class Big5Data {
 
 bits = []
 for (low, high) in astral_ranges:
-  for i in xrange(low, high):
+  for i in range(low, high):
     bits.append(1 if index[i] > 0xFFFF else 0)
 # pad length to multiple of 16
-for j in xrange(16 - (len(bits) % 16)):
+for j in range(16 - (len(bits) % 16)):
   bits.append(0)
 
 i = 0
 while i < len(bits):
   accu = 0
-  for j in xrange(16):
+  for j in range(16):
     accu |= bits[i + j] << j
   if accu == 0x22:
     class_file.write('\\"')
@@ -632,7 +632,7 @@ class_file.write('''";
 j = 0
 for (low, high) in ranges:
   class_file.write('''    private static final String TABLE%d = "''' % j)
-  for i in xrange(low, high):
+  for i in range(low, high):
     class_file.write('\\u%04X' % (index[i] & 0xFFFF))
   class_file.write('''";
 
@@ -704,7 +704,7 @@ prefer_last = [
 
 for code_point in prefer_last:
   # Python lists don't have .rindex() :-(
-  for i in xrange(len(index) - 1, -1, -1):
+  for i in range(len(index) - 1, -1, -1):
     candidate = index[i]
     if candidate == code_point:
        class_file.write('''                case 0x%04X:
diff --git a/python/PyECC/ecc/Key.py b/python/PyECC/ecc/Key.py
index 8ba2685768..998e03f610 100644
--- a/python/PyECC/ecc/Key.py
+++ b/python/PyECC/ecc/Key.py
@@ -168,11 +168,12 @@ prime having great security characteristics, 521 bits are preferred
 over a constructed 512 bit field.)
 """
 
-from encoding import *
-from eccrypt import *
-import ecdsa
+from __future__ import print_function
+from .encoding import *
+from .eccrypt import *
+from . import ecdsa
 import hashlib
-from SecurityViolationException import *
+from .SecurityViolationException import *
 
 class Key:
 
@@ -214,7 +215,7 @@ class Key:
         if kid == k.keyid():
             return k
         else:
-            raise ValueError, "Invalid Key ID"
+            raise ValueError("Invalid Key ID")
 
     # --- IDENTIFICATION AND VALIDATION ----------------------------------------
 
@@ -259,7 +260,7 @@ class Key:
             s = ecdsa.sign(h, self._priv)
             return enc_point(s)
         else:
-            raise AttributeError, "Private key needed for signing."
+            raise AttributeError("Private key needed for signing.")
 
     def verify(self, data, sig, hashfunc = 'sha256'):
         '''Verify the signature of data using the specified hash function'''
@@ -294,7 +295,7 @@ class Key:
         if source.verify(text, sgn):
             return text
         else:
-            raise SecurityViolationException, "Invalid Signature"
+            raise SecurityViolationException("Invalid Signature")
 
 
 if __name__ == "__main__":
@@ -302,7 +303,7 @@ if __name__ == "__main__":
     import time
 
     def test_overhead():
-        print "sender", "receiver", "+bytes", "+enctime", "+dectime"
+        print(("sender", "receiver", "+bytes", "+enctime", "+dectime"))
         for s in [192, 224, 256, 384, 521]:
             sender = Key.generate(s)
             for r in [192, 224, 256, 384, 521]:
@@ -313,7 +314,7 @@ if __name__ == "__main__":
                 t = time.time()
                 receiver.auth_decrypt(e, sender)
                 t2 = time.time() - t
-                print s, r, len(e), t1, t2
+                print((s, r, len(e), t1, t2))
 
                 
                 
diff --git a/python/PyECC/ecc/Rabbit.py b/python/PyECC/ecc/Rabbit.py
index 209f01e1ee..09a4a4994e 100644
--- a/python/PyECC/ecc/Rabbit.py
+++ b/python/PyECC/ecc/Rabbit.py
@@ -31,17 +31,17 @@ class Rabbit:
                 key = '\x00' * (16 - len(key)) + key
             # if len(key) > 16 bytes only the first 16 will be considered
             k = [ord(key[i + 1]) | (ord(key[i]) << 8)
-                 for i in xrange(14, -1, -2)]
+                 for i in range(14, -1, -2)]
         else:
             # k[0] = least significant 16 bits
             # k[7] = most significant 16 bits
-            k = [(key >> i) & 0xFFFF for i in xrange(0, 128, 16)]
+            k = [(key >> i) & 0xFFFF for i in range(0, 128, 16)]
             
         # State and counter initialization
         x = [(k[(j + 5) % 8] << 16) | k[(j + 4) % 8] if j & 1 else
-             (k[(j + 1) % 8] << 16) | k[j] for j in xrange(8)]
+             (k[(j + 1) % 8] << 16) | k[j] for j in range(8)]
         c = [(k[j] << 16) | k[(j + 1) % 8] if j & 1 else
-             (k[(j + 4) % 8] << 16) | k[(j + 5) % 8] for j in xrange(8)]
+             (k[(j + 4) % 8] << 16) | k[(j + 5) % 8] for j in range(8)]
         
         self.x = x
         self.c = c
@@ -49,12 +49,12 @@ class Rabbit:
         self._buf = 0           # output buffer
         self._buf_bytes = 0     # fill level of buffer
         
-        self.next()
-        self.next()
-        self.next()
-        self.next()
+        next(self)
+        next(self)
+        next(self)
+        next(self)
 
-        for j in xrange(8):
+        for j in range(8):
             c[j] ^= x[(j + 4) % 8]
         
         self.start_x = self.x[:]    # backup initial key for IV/reset
@@ -99,10 +99,10 @@ class Rabbit:
         c[6] ^= i2
         c[7] ^= i3
 
-        self.next()
-        self.next()
-        self.next()
-        self.next()
+        next(self)
+        next(self)
+        next(self)
+        next(self)
         
 
     def next(self):
@@ -130,7 +130,7 @@ class Rabbit:
         c[7] = t % WORDSIZE
         b = t // WORDSIZE
         
-        g = [_nsf(x[j], c[j]) for j in xrange(8)]
+        g = [_nsf(x[j], c[j]) for j in range(8)]
         
         x[0] = (g[0] + rot16(g[7]) + rot16(g[6])) % WORDSIZE
         x[1] = (g[1] + rot08(g[0]) + g[7]) % WORDSIZE
@@ -168,7 +168,7 @@ class Rabbit:
         next = self.next
         derive = self.derive
         
-        for i in xrange(n):
+        for i in range(n):
             if not j:
                 j = 16
                 next()
diff --git a/python/PyECC/ecc/curves.py b/python/PyECC/ecc/curves.py
index ee5847fc50..ecbcb55362 100644
--- a/python/PyECC/ecc/curves.py
+++ b/python/PyECC/ecc/curves.py
@@ -16,35 +16,35 @@ obfuscate non-critical transmissions.
 # (see FIPS 186-3, Appendix D.1.2)
 DOMAINS = {
     # Bits : (p, order of E(GF(P)), parameter b, base point x, base point y)
-    192 : (0xfffffffffffffffffffffffffffffffeffffffffffffffffL,
-           0xffffffffffffffffffffffff99def836146bc9b1b4d22831L,
-           0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1L,
-           0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012L,
-           0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811L),
+    192 : (0xfffffffffffffffffffffffffffffffeffffffffffffffff,
+           0xffffffffffffffffffffffff99def836146bc9b1b4d22831,
+           0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1,
+           0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012,
+           0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811),
     
-    224 : (0xffffffffffffffffffffffffffffffff000000000000000000000001L,
-           0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3dL,
-           0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4L,
-           0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21L,
-           0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34L),
+    224 : (0xffffffffffffffffffffffffffffffff000000000000000000000001,
+           0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d,
+           0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4,
+           0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21,
+           0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34),
 
-    256 : (0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffL,
-           0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551L,
-           0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bL,
-           0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296L,
-           0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5L),
+    256 : (0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff,
+           0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551,
+           0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b,
+           0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,
+           0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5),
 
-    384 : (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffL,
-           0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973L,
-           0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefL,
-           0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7L,
-           0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fL),
+    384 : (0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff,
+           0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973,
+           0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef,
+           0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7,
+           0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f),
 
-    521 : (0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffL,
-           0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409L,
-           0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00L,
-           0x0c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66L,
-           0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650L)
+    521 : (0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
+           0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409,
+           0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00,
+           0x0c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66,
+           0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650)
     }
 
 
@@ -52,17 +52,17 @@ DOMAINS = {
 # (not intended for use in signing, hence the missing group order)
 
 DOMAINS.update({
-    128 : (0xffffffffffffffffffffffffffffff61L,
+    128 : (0xffffffffffffffffffffffffffffff61,
            None,
-           0xd83d3eb8266a89927d73d5fe263d5f23L,
-           0xa94d2d8531f7af8bde367def12b98eadL,
-           0x9f44e1d671beb68fd2df7f877ab13fa6L),
+           0xd83d3eb8266a89927d73d5fe263d5f23,
+           0xa94d2d8531f7af8bde367def12b98ead,
+           0x9f44e1d671beb68fd2df7f877ab13fa6),
     
-    160 : (0xffffffffffffffffffffffffffffffffffffffd1L,
+    160 : (0xffffffffffffffffffffffffffffffffffffffd1,
            None,
-           0x94bfe70deef7b94742c089ca4db3ca27fbe1f754L,
-           0xcc6562c2969ac57524b8d0f300d1f598c908c121L,
-           0x952ddde80a252683dd7ba90fb5919899b5af69f5L)
+           0x94bfe70deef7b94742c089ca4db3ca27fbe1f754,
+           0xcc6562c2969ac57524b8d0f300d1f598c908c121,
+           0x952ddde80a252683dd7ba90fb5919899b5af69f5)
     })     
 
 CURVE_P = 3     # global parameter of all curves (for efficiency reasons)
@@ -75,7 +75,7 @@ def get_curve(bits):
         p, n, b, x, y = DOMAINS[bits]
         return bits, p, n, CURVE_P, p - b, (x, y)
     else:
-        raise KeyError, "Key size not implemented: %s" % bits
+        raise KeyError("Key size not implemented: %s" % bits)
  
 def implemented_keys(must_sign = False):
     return [k for k in DOMAINS if not must_sign or DOMAINS[k][1]]
diff --git a/python/PyECC/ecc/eccrypt.py b/python/PyECC/ecc/eccrypt.py
index c38876d071..c9fadee46a 100644
--- a/python/PyECC/ecc/eccrypt.py
+++ b/python/PyECC/ecc/eccrypt.py
@@ -3,11 +3,11 @@
 #   COPYRIGHT (c) 2010 by Toni Mattis <solaris@live.de>
 #
 
-from curves import get_curve
-from elliptic import mulp
-from encoding import enc_long
+from .curves import get_curve
+from .elliptic import mulp
+from .encoding import enc_long
 from random import SystemRandom
-from Rabbit import Rabbit
+from .Rabbit import Rabbit
 
 # important for cryptographically secure random numbers:
 random = SystemRandom()
@@ -31,9 +31,9 @@ def encrypt(message, qk, encrypter = Rabbit):
     try:
         bits, cn, n, cp, cq, g = get_curve(bits)
         if not n:
-            raise ValueError, "Key size %s not suitable for encryption" % bits
+            raise ValueError("Key size %s not suitable for encryption" % bits)
     except KeyError:
-        raise ValueError, "Key size %s not implemented" % bits
+        raise ValueError("Key size %s not implemented" % bits)
     
     k = random.randint(1, n - 1)        # temporary private key k
     kg = mulp(cp, cq, cn, g, k)         # temporary public key k*G
@@ -57,7 +57,7 @@ def decrypt(message, kg, dk, decrypter = Rabbit):
     try:
         bits, cn, n, cp, cq, g = get_curve(bits)
     except KeyError:
-        raise ValueError, "Key size %s not implemented" % bits
+        raise ValueError("Key size %s not implemented" % bits)
 
     sg = mulp(cp, cq, cn, kg, d)        # shared secret d*(k*G) = k*d*G
     return decrypter(enc_long(sg[0])).decrypt(message)
diff --git a/python/PyECC/ecc/ecdsa.py b/python/PyECC/ecc/ecdsa.py
index 6b52aeaa5d..b558ebd58d 100644
--- a/python/PyECC/ecc/ecdsa.py
+++ b/python/PyECC/ecc/ecdsa.py
@@ -4,8 +4,8 @@
 #   COPYRIGHT (c) 2010 by Toni Mattis <solaris@live.de>
 #
 
-from elliptic import inv, mulf, mulp, muladdp, element
-from curves import get_curve, implemented_keys
+from .elliptic import inv, mulf, mulp, muladdp, element
+from .curves import get_curve, implemented_keys
 from os import urandom
 
 import hashlib
@@ -23,13 +23,13 @@ def keypair(bits):
     try:
         bits, cn, n, cp, cq, g = get_curve(bits)
     except KeyError:
-        raise ValueError, "Key size %s not implemented" % bits
+        raise ValueError("Key size %s not implemented" % bits)
     if n > 0:
         d = randkey(bits, n)
         q = mulp(cp, cq, cn, g, d)
         return (bits, q), (bits, d)
     else:
-        raise ValueError, "Key size %s not suitable for signing" % bits
+        raise ValueError("Key size %s not suitable for signing" % bits)
 
 def supported_keys():
     '''Return a list of all key sizes implemented for signing'''
@@ -134,17 +134,17 @@ if __name__ == "__main__":
         d = get_curve(bits)
         
         t = time.time()
-        for i in xrange(rounds):
+        for i in range(rounds):
             qk, dk = keypair(bits)
         tgen = time.time() - t
         
         t = time.time()
-        for i in xrange(rounds):
+        for i in range(rounds):
             s = sign(0, dk)
         tsign = time.time() - t
 
         t = time.time()
-        for i in xrange(rounds):
+        for i in range(rounds):
             verify(0, s, qk)
         tver = time.time() - t
 
diff --git a/python/PyECC/ecc/elliptic.py b/python/PyECC/ecc/elliptic.py
index 9191a88488..0133a308e5 100644
--- a/python/PyECC/ecc/elliptic.py
+++ b/python/PyECC/ecc/elliptic.py
@@ -1,4 +1,3 @@
-
 # --- ELLIPTIC CURVE MATH ------------------------------------------------------
 #
 #   curve definition:   y^2 = x^3 - p*x - q
@@ -360,9 +359,9 @@ if __name__ == "__main__":
         q = curve_q(p1[0], p1[1], p, n)
         p2 = mulp(p, q, n, p1, rsa.random.randint(1, n))
 
-        c1 = [rsa.random.randint(1, n) for i in xrange(tcount)]
-        c2 = [rsa.random.randint(1, n) for i in xrange(tcount)]
-        c = zip(c1, c2)
+        c1 = [rsa.random.randint(1, n) for i in range(tcount)]
+        c2 = [rsa.random.randint(1, n) for i in range(tcount)]
+        c = list(zip(c1, c2))
 
         t = time.time()
         for i, j in c:
diff --git a/python/PyECC/ecc/encoding.py b/python/PyECC/ecc/encoding.py
index 24d3eb5a89..4b474295ae 100644
--- a/python/PyECC/ecc/encoding.py
+++ b/python/PyECC/ecc/encoding.py
@@ -158,7 +158,7 @@ class Decoder:
             self._parent._res.append(self._res)
             return self._parent
         else:
-            raise RuntimeError, "Cannont exit top level Decoder"
+            raise RuntimeError("Cannont exit top level Decoder")
 
     def continues(self):
         return (not self._limit) or (self._io.tell() < self._limit)
diff --git a/python/PyECC/ecc/performance.py b/python/PyECC/ecc/performance.py
index 724176aef8..55787868d4 100644
--- a/python/PyECC/ecc/performance.py
+++ b/python/PyECC/ecc/performance.py
@@ -36,13 +36,11 @@ def test_verification_perf(n = 100):
     return results
             
 def print_dict(title, d):
-    print title
-    print '-' * len(title)
+    print(title)
+    print('-' * len(title))
     for k, v in d.items():
-        print k, '\t', v
-    print
-
-n = 100
+        print(k, '\t', v)
+    print(n = 100)
 print_dict("Key generation", test_generation_perf(n))
 print_dict("Signing", test_signing_perf(n))
 print_dict("Verifying", test_verification_perf(n))
diff --git a/python/PyECC/ecc/primes.py b/python/PyECC/ecc/primes.py
index a8bc1424bf..7e2cb7953c 100644
--- a/python/PyECC/ecc/primes.py
+++ b/python/PyECC/ecc/primes.py
@@ -33,14 +33,14 @@ def prime(n, k):
         s += 1
         d /= 2
         
-    for i in xrange(k):
+    for i in range(k):
         
-        a = long(2 + random.randint(0, n - 4))
+        a = int(2 + random.randint(0, n - 4))
         x = exp(a, d, n)
         if (x == 1) or (x == n - 1):
             continue
         
-        for r in xrange(1, s):
+        for r in range(1, s):
             x = (x * x) % n
             
             if x == 1:
diff --git a/python/PyECC/ecc/shacrypt.py b/python/PyECC/ecc/shacrypt.py
index 69ee7b9433..d637bcb7d2 100644
--- a/python/PyECC/ecc/shacrypt.py
+++ b/python/PyECC/ecc/shacrypt.py
@@ -17,7 +17,7 @@ BPOS = tuple(range(64))
 def enc_block(block, key, rounds = 16):
     x = block[:64]
     y = block[64:]
-    for i in xrange(rounds):
+    for i in range(rounds):
         h = sha512(x + key).digest()
         y = ''.join([chr(ord(y[k]) ^ ord(h[k])) for k in BPOS])
         h = sha512(y + key).digest()
@@ -27,7 +27,7 @@ def enc_block(block, key, rounds = 16):
 def dec_block(block, key, rounds = 16):
     x = block[:64]
     y = block[64:]
-    for i in xrange(rounds):
+    for i in range(rounds):
         h = sha512(y + key).digest()
         x = ''.join([chr(ord(x[k]) ^ ord(h[k])) for k in BPOS])
         h = sha512(x + key).digest()
diff --git a/python/altgraph/altgraph/Dot.py b/python/altgraph/altgraph/Dot.py
index 49a471e4da..4629376283 100644
--- a/python/altgraph/altgraph/Dot.py
+++ b/python/altgraph/altgraph/Dot.py
@@ -108,7 +108,7 @@ import warnings
 from altgraph import GraphError
 
 
-class Dot(object):
+class Dot:
     '''
     A  class providing a **graphviz** (dot language) representation
     allowing a fine grained control over how the graph is being
@@ -180,12 +180,12 @@ class Dot(object):
 
         if  mode == 'neato':
             self.save_dot(self.temp_neo)
-            neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo)
+            neato_cmd = "{} -o {} {}".format(self.neato, self.temp_dot, self.temp_neo)
             os.system(neato_cmd)
         else:
             self.save_dot(self.temp_dot)
 
-        plot_cmd = "%s %s" % (self.dotty, self.temp_dot)
+        plot_cmd = "{} {}".format(self.dotty, self.temp_dot)
         os.system(plot_cmd)
 
     def node_style(self, node, **kwargs):
@@ -208,28 +208,28 @@ class Dot(object):
         Modifies an edge style to the dot representation.
         '''
         if tail not in self.nodes:
-            raise GraphError("invalid node %s" % (tail,))
+            raise GraphError("invalid node {}".format(tail))
 
         try:
             if tail not in self.edges[head]:
                 self.edges[head][tail]= {}
             self.edges[head][tail] = kwargs
         except KeyError:
-            raise GraphError("invalid edge  %s -> %s " % (head, tail) )
+            raise GraphError("invalid edge  {} -> {} ".format(head, tail) )
 
     def iterdot(self):
         # write graph title
         if self.type == 'digraph':
-            yield 'digraph %s {\n' % (self.name,)
+            yield 'digraph {} {{\n'.format(self.name)
         elif self.type == 'graph':
-            yield 'graph %s {\n' % (self.name,)
+            yield 'graph {} {{\n'.format(self.name)
 
         else:
-            raise GraphError("unsupported graphtype %s" % (self.type,))
+            raise GraphError("unsupported graphtype {}".format(self.type))
 
         # write overall graph attributes
         for attr_name, attr_value in sorted(self.attr.items()):
-            yield '%s="%s";' % (attr_name, attr_value)
+            yield '{}="{}";'.format(attr_name, attr_value)
         yield '\n'
 
         # some reusable patterns
@@ -238,7 +238,7 @@ class Dot(object):
 
         # write node attributes
         for node_name, node_attr in sorted(self.nodes.items()):
-            yield '\t"%s" [' % (node_name,)
+            yield '\t"{}" ['.format(node_name)
             for attr_name, attr_value in sorted(node_attr.items()):
                 yield cpatt % (attr_name, attr_value)
             yield epatt
@@ -247,9 +247,9 @@ class Dot(object):
         for head in sorted(self.edges):
             for tail in sorted(self.edges[head]):
                 if self.type == 'digraph':
-                    yield '\t"%s" -> "%s" [' % (head, tail)
+                    yield '\t"{}" -> "{}" ['.format(head, tail)
                 else:
-                    yield '\t"%s" -- "%s" [' % (head, tail)
+                    yield '\t"{}" -- "{}" ['.format(head, tail)
                 for attr_name, attr_value in sorted(self.edges[head][tail].items()):
                     yield cpatt % (attr_name, attr_value)
                 yield epatt
@@ -287,13 +287,13 @@ class Dot(object):
 
         if  mode == 'neato':
             self.save_dot(self.temp_neo)
-            neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo)
+            neato_cmd = "{} -o {} {}".format(self.neato, self.temp_dot, self.temp_neo)
             os.system(neato_cmd)
             plot_cmd = self.dot
         else:
             self.save_dot(self.temp_dot)
             plot_cmd = self.dot
 
-        file_name  = "%s.%s" % (file_name, file_type)
-        create_cmd = "%s -T%s %s -o %s" % (plot_cmd, file_type, self.temp_dot, file_name)
+        file_name  = "{}.{}".format(file_name, file_type)
+        create_cmd = "{} -T{} {} -o {}".format(plot_cmd, file_type, self.temp_dot, file_name)
         os.system(create_cmd)
diff --git a/python/altgraph/altgraph/Graph.py b/python/altgraph/altgraph/Graph.py
index 491e5c2287..fc619e4e07 100644
--- a/python/altgraph/altgraph/Graph.py
+++ b/python/altgraph/altgraph/Graph.py
@@ -16,7 +16,7 @@ altgraph.Graph - Base Graph class
 from altgraph import GraphError
 from collections import deque
 
-class Graph(object):
+class Graph:
     """
     The Graph class represents a directed graph with *N* nodes and *E* edges.
 
@@ -110,7 +110,7 @@ class Graph(object):
             self.nodes[tail_id][0].append(edge)
             self.nodes[head_id][1].append(edge)
         except KeyError:
-            raise GraphError('Invalid nodes %s -> %s' % (head_id, tail_id))
+            raise GraphError('Invalid nodes {} -> {}'.format(head_id, tail_id))
 
         # store edge information
         self.edges[edge] = (head_id, tail_id, edge_data)
@@ -491,7 +491,7 @@ class Graph(object):
         The forward parameter specifies whether it is a forward or backward
         traversal.
         """
-        visited, stack = set([start]), deque([start])
+        visited, stack = {start}, deque([start])
 
         if forward:
             get_edges = self.out_edges
@@ -518,7 +518,7 @@ class Graph(object):
         condition callback is only called when node_data is not None.
         """
 
-        visited, stack = set([start]), deque([start])
+        visited, stack = {start}, deque([start])
 
         if forward:
             get_edges = self.out_edges
@@ -550,7 +550,7 @@ class Graph(object):
         traversal.  Returns a list of tuples where the first value is the hop
         value the second value is the node id.
         """
-        queue, visited = deque([(start, 0)]), set([start])
+        queue, visited = deque([(start, 0)]), {start}
 
         # the direction of the bfs depends on the edges that are sampled
         if forward:
diff --git a/python/altgraph/altgraph/GraphAlgo.py b/python/altgraph/altgraph/GraphAlgo.py
index 9e6fff2b17..2cd4a4ee18 100644
--- a/python/altgraph/altgraph/GraphAlgo.py
+++ b/python/altgraph/altgraph/GraphAlgo.py
@@ -127,7 +127,7 @@ class _priorityDictionary(dict):
         dict.__setitem__(self,key,val)
         heap = self.__heap
         if len(heap) > 2 * len(self):
-            self.__heap = [(v,k) for k,v in self.iteritems()]
+            self.__heap = [(v,k) for k,v in self.items()]
             self.__heap.sort()  # builtin sort probably faster than O(n)-time heapify
         else:
             newPair = (val,key)
diff --git a/python/altgraph/altgraph/GraphUtil.py b/python/altgraph/altgraph/GraphUtil.py
index d3b6acd74d..f33440161b 100644
--- a/python/altgraph/altgraph/GraphUtil.py
+++ b/python/altgraph/altgraph/GraphUtil.py
@@ -24,7 +24,7 @@ def generate_random_graph(node_num, edge_num, self_loops=False, multi_edges=Fals
         if edge_num > max_edges:
             raise GraphError("inconsistent arguments to 'generate_random_graph'")
 
-    nodes = range(node_num)
+    nodes = list(range(node_num))
 
     for node in nodes:
         g.add_node(node)
@@ -49,7 +49,7 @@ def generate_random_graph(node_num, edge_num, self_loops=False, multi_edges=Fals
     return g
 
 def generate_scale_free_graph(steps, growth_num, self_loops=False, multi_edges=False):
-    '''
+    r'''
     Generates and returns a :py:class:`~altgraph.Graph.Graph` instance that will have *steps* \* *growth_num* nodes
     and a scale free (powerlaw) connectivity. Starting with a fully connected graph with *growth_num* nodes
     at every step *growth_num* nodes are added to the graph and are connected to existing nodes with
@@ -107,7 +107,7 @@ def filter_stack(graph, head, filters):
       in *removes*.
     """
 
-    visited, removes, orphans = set([head]), set(), set()
+    visited, removes, orphans = {head}, set(), set()
     stack = deque([(head, head)])
     get_data = graph.node_data
     get_edges = graph.out_edges
diff --git a/python/altgraph/altgraph/ObjectGraph.py b/python/altgraph/altgraph/ObjectGraph.py
index d07f51b688..810a8362cb 100644
--- a/python/altgraph/altgraph/ObjectGraph.py
+++ b/python/altgraph/altgraph/ObjectGraph.py
@@ -6,11 +6,12 @@ A graph of objects that have a "graphident" attribute.
 graphident is the key for the object in the graph
 """
 
+from __future__ import print_function
 from altgraph import GraphError
 from altgraph.Graph import Graph
 from altgraph.GraphUtil import filter_stack
 
-class ObjectGraph(object):
+class ObjectGraph:
     """
     A graph of objects that have a "graphident" attribute.
     graphident is the key for the object in the graph
@@ -25,7 +26,7 @@ class ObjectGraph(object):
         graph.add_node(self, None)
 
     def __repr__(self):
-        return '<%s>' % (type(self).__name__,)
+        return '<{}>'.format(type(self).__name__)
 
     def flatten(self, condition=None, start=None):
         """
@@ -183,7 +184,7 @@ class ObjectGraph(object):
         Print a debug message with the given level
         """
         if s and level <= self.debug:
-            print ("%s%s %s" % ("  " * self.indent, s, ' '.join(map(repr, args))))
+            print(("{}{} {}".format("  " * self.indent, s, ' '.join(map(repr, args)))))
 
     def msgin(self, level, s, *args):
         """
diff --git a/python/altgraph/altgraph_tests/test_dot.py b/python/altgraph/altgraph_tests/test_dot.py
index 83993dad54..0903502507 100644
--- a/python/altgraph/altgraph_tests/test_dot.py
+++ b/python/altgraph/altgraph_tests/test_dot.py
@@ -32,7 +32,7 @@ class TestDot (unittest.TestCase):
         self.assertEqual(dot.neato, 'neato')
         self.assertEqual(dot.type, 'digraph')
 
-        self.assertEqual(dot.nodes, dict([(x, {}) for x in g]))
+        self.assertEqual(dot.nodes, {x: {} for x in g})
 
         edges = {}
         for head in g:
@@ -63,7 +63,7 @@ class TestDot (unittest.TestCase):
         self.assertEqual(dot.neato, '/usr/local/bin/neato')
         self.assertEqual(dot.type, 'graph')
 
-        self.assertEqual(dot.nodes, dict([(x, {'label': x}) for x in [1,2]]))
+        self.assertEqual(dot.nodes, {x: {'label': x} for x in [1,2]})
 
         edges = {}
         for head in [1,2]:
@@ -271,7 +271,7 @@ class TestDot (unittest.TestCase):
         try:
             dot.save_dot(fn)
 
-            fp = open(fn, 'r')
+            fp = open(fn)
             data = fp.read()
             fp.close()
             self.assertEqual(data, ''.join(dot))
diff --git a/python/altgraph/altgraph_tests/test_graphutil.py b/python/altgraph/altgraph_tests/test_graphutil.py
index c1166237c1..ef618e5da2 100644
--- a/python/altgraph/altgraph_tests/test_graphutil.py
+++ b/python/altgraph/altgraph_tests/test_graphutil.py
@@ -107,11 +107,11 @@ class TestGraphUtil (unittest.TestCase):
             lambda n: n != "N.1.1.1", lambda n: n != "N.1.1.2.3" ])
 
         self.assertEqual(v,
-            set(["1", "1.1", "1.1.1", "1.1.2", "1.1.3",
+            {"1", "1.1", "1.1.1", "1.1.2", "1.1.3",
                 "1.1.1.1", "1.1.1.2", "1.1.2.1", "1.1.2.2",
-                "1.1.2.3"]))
-        self.assertEqual(r, set([
-                "1.1.1", "1.1.2.3"]))
+                "1.1.2.3"})
+        self.assertEqual(r, {
+                "1.1.1", "1.1.2.3"})
 
         o.sort()
         self.assertEqual(o,
@@ -124,11 +124,11 @@ class TestGraphUtil (unittest.TestCase):
             lambda n: n != "N.1.1.1", lambda n: n != "N.1.1.1.2" ])
 
         self.assertEqual(v,
-            set(["1", "1.1", "1.1.1", "1.1.2", "1.1.3",
+            {"1", "1.1", "1.1.1", "1.1.2", "1.1.3",
                 "1.1.1.1", "1.1.1.2", "1.1.2.1", "1.1.2.2",
-                "1.1.2.3"]))
-        self.assertEqual(r, set([
-                "1.1.1", "1.1.1.2"]))
+                "1.1.2.3"})
+        self.assertEqual(r, {
+                "1.1.1", "1.1.1.2"})
 
         self.assertEqual(o,
             [
diff --git a/python/altgraph/altgraph_tests/test_object_graph.py b/python/altgraph/altgraph_tests/test_object_graph.py
index 9035607e7a..004a623324 100644
--- a/python/altgraph/altgraph_tests/test_object_graph.py
+++ b/python/altgraph/altgraph_tests/test_object_graph.py
@@ -9,14 +9,14 @@ except ImportError:
     from io import StringIO
 
 
-class Node (object):
+class Node :
     def __init__(self, graphident):
         self.graphident = graphident
 
 class SubNode (Node):
     pass
 
-class ArgNode (object):
+class ArgNode :
     def __init__(self, graphident, *args, **kwds):
         self.graphident = graphident
         self.args = args
diff --git a/python/altgraph/doc/conf.py b/python/altgraph/doc/conf.py
index cd3fd9912e..3d5e2ace75 100644
--- a/python/altgraph/doc/conf.py
+++ b/python/altgraph/doc/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # altgraph documentation build configuration file, created by
 # sphinx-quickstart on Tue Aug 31 11:04:49 2010.
@@ -48,8 +47,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'altgraph'
-copyright = u'2010-2011, Ronald Oussoren, Bob Ippolito, 2004 Istvan Albert'
+project = 'altgraph'
+copyright = '2010-2011, Ronald Oussoren, Bob Ippolito, 2004 Istvan Albert'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -183,8 +182,8 @@ htmlhelp_basename = 'altgraphdoc'
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'altgraph.tex', u'altgraph Documentation',
-   u'Ronald Oussoren', 'manual'),
+  ('index', 'altgraph.tex', 'altgraph Documentation',
+   'Ronald Oussoren', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
diff --git a/python/altgraph/setup.py b/python/altgraph/setup.py
index a1a4cb6eb2..15913a4417 100644
--- a/python/altgraph/setup.py
+++ b/python/altgraph/setup.py
@@ -15,6 +15,7 @@ Additional functionality:
 
 """
 
+from __future__ import print_function
 import sys
 import os
 import re
@@ -28,7 +29,7 @@ import tarfile
 try:
     import urllib.request as urllib
 except ImportError:
-    import urllib
+    import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 from distutils import log
 try:
     from hashlib import md5
@@ -36,10 +37,7 @@ try:
 except ImportError:
     from md5 import md5
 
-if sys.version_info[0] == 2:
-    from ConfigParser import RawConfigParser, NoOptionError, NoSectionError
-else:
-    from configparser import RawConfigParser, NoOptionError, NoSectionError
+from configparser import RawConfigParser, NoOptionError, NoSectionError
 
 ROOTDIR = os.path.dirname(os.path.abspath(__file__))
 
@@ -226,7 +224,7 @@ def parse_setup_cfg():
     else:
         parts = []
         for nm in v.split():
-            fp = open(nm, 'rU')
+            fp = open(nm)
             parts.append(fp.read())
             fp.close()
 
@@ -295,7 +293,7 @@ try:
 
     def get_pypi_src_download(package):
         url = 'https://pypi.python.org/pypi/%s/json'%(package,)
-        fp = urllib.urlopen(url)
+        fp = six.moves.urllib.request.urlopen(url)
         try:
             try:
                 data = fp.read()
@@ -323,7 +321,7 @@ except ImportError:
 
     def get_pypi_src_download(package):
         url = 'https://pypi.python.org/pypi/%s/json'%(package,)
-        fp = urllib.urlopen(url)
+        fp = six.moves.urllib.request.urlopen(url)
         try:
             try:
                 data = fp.read()
@@ -412,7 +410,7 @@ def _build_egg(egg, tarball, to_dir):
     # returning the result
     log.warn(egg)
     if not os.path.exists(egg):
-        raise IOError('Could not build the egg.')
+        raise OSError('Could not build the egg.')
 
 
 def _do_download(to_dir, packagename=SETUPTOOLS_PACKAGE):
@@ -437,7 +435,7 @@ def download_setuptools(packagename, to_dir):
     try:
         from urllib.request import urlopen
     except ImportError:
-        from urllib2 import urlopen
+        from urllib.request import urlopen
 
     chksum, url = get_pypi_src_download(packagename)
     tgz_name = os.path.basename(url)
@@ -579,11 +577,11 @@ else:
             import shutil
             import zipfile
             import os
-            import urllib
+            import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
             import StringIO
             from base64 import standard_b64encode
-            import httplib
-            import urlparse
+            import six.moves.http_client
+            import six.moves.urllib.parse
 
             # Extract the package name from distutils metadata
             meta = self.distribution.metadata
@@ -611,7 +609,7 @@ else:
                     fullname = os.path.join(toplevel, fn)
                     relname = os.path.relpath(fullname, 'doc/_build/html')
 
-                    print ("%s -> %s"%(fullname, relname))
+                    print(("%s -> %s"%(fullname, relname)))
 
                     zf.write(fullname, relname)
 
@@ -658,13 +656,13 @@ else:
             self.announce("Uploading documentation to %s"%(self.repository,), log.INFO)
 
             schema, netloc, url, params, query, fragments = \
-                    urlparse.urlparse(self.repository)
+                    six.moves.urllib.parse.urlparse(self.repository)
 
 
             if schema == 'http':
-                http = httplib.HTTPConnection(netloc)
+                http = six.moves.http_client.HTTPConnection(netloc)
             elif schema == 'https':
-                http = httplib.HTTPSConnection(netloc)
+                http = six.moves.http_client.HTTPSConnection(netloc)
             else:
                 raise AssertionError("unsupported schema "+schema)
 
@@ -679,22 +677,22 @@ else:
                 http.putheader('Authorization', auth)
                 http.endheaders()
                 http.send(body)
-            except socket.error:
+            except OSError:
                 e = socket.exc_info()[1]
                 self.announce(str(e), log.ERROR)
                 return
 
             r = http.getresponse()
             if r.status in (200, 301):
-                self.announce('Upload succeeded (%s): %s' % (r.status, r.reason),
+                self.announce('Upload succeeded ({}): {}'.format(r.status, r.reason),
                     log.INFO)
             else:
-                self.announce('Upload failed (%s): %s' % (r.status, r.reason),
+                self.announce('Upload failed ({}): {}'.format(r.status, r.reason),
                     log.ERROR)
 
-                print ('-'*75)
-                print (r.read())
-                print ('-'*75)
+                print(('-'*75))
+                print((r.read()))
+                print(('-'*75))
 
 
 def recursiveGlob(root, pathPattern):
@@ -718,7 +716,7 @@ def importExternalTestCases(unittest,
     """
 
     testFiles = recursiveGlob(root, pathPattern)
-    testModules = map(lambda x:x[len(root)+1:-3].replace('/', '.'), testFiles)
+    testModules = [x[len(root)+1:-3].replace('/', '.') for x in testFiles]
     if package is not None:
         testModules = [(package + '.' + m) for m in testModules]
 
@@ -728,7 +726,7 @@ def importExternalTestCases(unittest,
         try:
             module = __import__(modName)
         except ImportError:
-            print("SKIP %s: %s"%(modName, sys.exc_info()[1]))
+            print(("SKIP %s: %s"%(modName, sys.exc_info()[1])))
             continue
 
         if '.' in modName:
@@ -843,7 +841,7 @@ class test (Command):
                 xpass=len(getattr(result, 'expectedSuccesses', [])),
                 skip=len(getattr(result, 'skipped', [])),
             )
-            print("SUMMARY: %s"%(summary,))
+            print(("SUMMARY: %s"%(summary,)))
 
         finally:
             self.remove_from_sys_path()
diff --git a/python/bitstring/bitstring.py b/python/bitstring/bitstring.py
index 86f969c7f2..b7af104ee5 100644
--- a/python/bitstring/bitstring.py
+++ b/python/bitstring/bitstring.py
@@ -13,12 +13,12 @@ BitStream -- A mutable container with streaming methods.
 
                       Bits (base class)
                      /    \
- + mutating methods /      \ + streaming methods
+ + mutating methods /      \\ + streaming methods
                    /        \
               BitArray   ConstBitStream
-                   \        /
-                    \      /
-                     \    /
+                   \\        /
+                    \\      /
+                     \\    /
                     BitStream
 
 Functions:
@@ -127,7 +127,7 @@ class CreationError(Error, ValueError):
         Error.__init__(self, *params)
 
 
-class ConstByteStore(object):
+class ConstByteStore:
     """Stores raw bytes together with a bit offset and length.
 
     Used internally - not part of public interface.
@@ -391,7 +391,7 @@ def equal(a, b):
     return a_val == b_val
 
 
-class MmapByteArray(object):
+class MmapByteArray:
     """Looks like a bytearray, but from an mmap.
 
     Not part of public interface.
@@ -446,13 +446,13 @@ BYTE_REVERSAL_DICT = dict()
 try:
     xrange
     for i in range(256):
-        BYTE_REVERSAL_DICT[i] = chr(int("{0:08b}".format(i)[::-1], 2))
+        BYTE_REVERSAL_DICT[i] = chr(int("{:08b}".format(i)[::-1], 2))
 except NameError:
     for i in range(256):
-        BYTE_REVERSAL_DICT[i] = bytes([int("{0:08b}".format(i)[::-1], 2)])
+        BYTE_REVERSAL_DICT[i] = bytes([int("{:08b}".format(i)[::-1], 2)])
     from io import IOBase as file
     xrange = range
-    basestring = str
+    str = str
 
 # Python 2.x octals start with '0', in Python 3 it's '0o'
 LEADING_OCT_CHARS = len(oct(1)) - 1
@@ -588,7 +588,7 @@ def tokenparser(fmt, keys=None, token_cache={}):
                 # and if you don't specify a 'name' then the default is 'uint':
                 m2 = DEFAULT_UINT.match(token)
                 if not m2:
-                    raise ValueError("Don't understand token '{0}'.".format(token))
+                    raise ValueError("Don't understand token '{}'.".format(token))
             if m1:
                 name = m1.group('name')
                 length = m1.group('len')
@@ -619,7 +619,7 @@ def tokenparser(fmt, keys=None, token_cache={}):
                     raise ValueError("Can't read a token with a negative length.")
                 except ValueError:
                     if not keys or length not in keys:
-                        raise ValueError("Don't understand length '{0}' of token.".format(length))
+                        raise ValueError("Don't understand length '{}' of token.".format(length))
             ret_vals.append([name, length, value])
         # This multiplies by the multiplicative factor, but this means that
         # we can't allow keyword values as multipliers (e.g. n*uint:8).
@@ -653,7 +653,7 @@ def expand_brackets(s):
                 break
             p += 1
         if count:
-            raise ValueError("Unbalanced parenthesis in '{0}'.".format(s))
+            raise ValueError("Unbalanced parenthesis in '{}'.".format(s))
         if start == 0 or s[start - 1] != '*':
             s = s[0:start] + s[start + 1:p] + s[p + 1:]
         else:
@@ -663,18 +663,18 @@ def expand_brackets(s):
                 matchstart = m.start('factor')
                 s = s[0:matchstart] + (factor - 1) * (s[start + 1:p] + ',') + s[start + 1:p] + s[p + 1:]
             else:
-                raise ValueError("Failed to parse '{0}'.".format(s))
+                raise ValueError("Failed to parse '{}'.".format(s))
     return s
 
 
 # This converts a single octal digit to 3 bits.
-OCT_TO_BITS = ['{0:03b}'.format(i) for i in xrange(8)]
+OCT_TO_BITS = ['{:03b}'.format(i) for i in range(8)]
 
 # A dictionary of number of 1 bits contained in binary representation of any byte
-BIT_COUNT = dict(zip(xrange(256), [bin(i).count('1') for i in xrange(256)]))
+BIT_COUNT = dict(zip(range(256), [bin(i).count('1') for i in range(256)]))
 
 
-class Bits(object):
+class Bits:
     """A container holding an immutable sequence of bits.
 
     For a mutable container use the BitArray class instead.
@@ -772,7 +772,7 @@ class Bits(object):
         # For instances auto-initialised with a string we intern the
         # instance for re-use.
         try:
-            if isinstance(auto, basestring):
+            if isinstance(auto, str):
                 try:
                     return _cache[auto]
                 except KeyError:
@@ -792,7 +792,7 @@ class Bits(object):
                 return auto
         except TypeError:
             pass
-        x = super(Bits, cls).__new__(cls)
+        x = super().__new__(cls)
         x._initialise(auto, length, offset, **kwargs)
         return x
 
@@ -843,16 +843,16 @@ class Bits(object):
         return self
 
     def __lt__(self, other):
-        raise TypeError("unorderable type: {0}".format(type(self).__name__))
+        raise TypeError("unorderable type: {}".format(type(self).__name__))
 
     def __gt__(self, other):
-        raise TypeError("unorderable type: {0}".format(type(self).__name__))
+        raise TypeError("unorderable type: {}".format(type(self).__name__))
 
     def __le__(self, other):
-        raise TypeError("unorderable type: {0}".format(type(self).__name__))
+        raise TypeError("unorderable type: {}".format(type(self).__name__))
 
     def __ge__(self, other):
-        raise TypeError("unorderable type: {0}".format(type(self).__name__))
+        raise TypeError("unorderable type: {}".format(type(self).__name__))
 
     def __add__(self, bs):
         """Concatenate bitstrings and return new bitstring.
@@ -967,14 +967,14 @@ class Bits(object):
             if self._datastore.byteoffset or self._offset:
                 offsetstring = ", offset=%d" % (self._datastore._rawarray.byteoffset * 8 + self._offset)
             lengthstring = ", length=%d" % length
-            return "{0}(filename='{1}'{2}{3})".format(self.__class__.__name__,
+            return "{}(filename='{}'{}{})".format(self.__class__.__name__,
                     self._datastore._rawarray.source.name, lengthstring, offsetstring)
         else:
             s = self.__str__()
             lengthstring = ''
             if s.endswith('...'):
-                lengthstring = " # length={0}".format(length)
-            return "{0}('{1}'){2}".format(self.__class__.__name__, s, lengthstring)
+                lengthstring = " # length={}".format(length)
+            return "{}('{}'){}".format(self.__class__.__name__, s, lengthstring)
 
     def __eq__(self, bs):
         """Return True if two bitstrings have the same binary representation.
@@ -1195,7 +1195,7 @@ class Bits(object):
     def _assertsanity(self):
         """Check internal self consistency as a debugging aid."""
         assert self.len >= 0
-        assert 0 <= self._offset, "offset={0}".format(self._offset)
+        assert 0 <= self._offset, "offset={}".format(self._offset)
         assert (self.len + self._offset + 7) // 8 == self._datastore.bytelength + self._datastore.byteoffset
         return True
 
@@ -1211,9 +1211,9 @@ class Bits(object):
 
         if value is None:
             if token_length is None:
-                error = "Token has no value ({0}=???).".format(name)
+                error = "Token has no value ({}=???).".format(name)
             else:
-                error = "Token has no value ({0}:{1}=???).".format(name, token_length)
+                error = "Token has no value ({}:{}=???).".format(name, token_length)
             raise ValueError(error)
         try:
             b = cls(**{_tokenname_to_initialiser[name]: value})
@@ -1270,7 +1270,7 @@ class Bits(object):
             raise CreationError("The length keyword isn't applicable to this initialiser.")
         if offset:
             raise CreationError("The offset keyword isn't applicable to this initialiser.")
-        if isinstance(s, basestring):
+        if isinstance(s, str):
             bs = self._converttobitstring(s)
             assert bs._offset == 0
             self._setbytes_unsafe(bs._datastore.rawbytes, bs.length, 0)
@@ -1286,11 +1286,11 @@ class Bits(object):
             data = bytearray((s + 7) // 8)
             self._datastore = ByteStore(data, s, 0)
             return
-        if isinstance(s, collections.Iterable):
+        if isinstance(s, collections.abc.Iterable):
             # Evaluate each item as True or False and set bits to 1 or 0.
             self._setbin_unsafe(''.join(str(int(bool(x))) for x in s))
             return
-        raise TypeError("Cannot initialise bitstring from {0}.".format(type(s)))
+        raise TypeError("Cannot initialise bitstring from {}.".format(type(s)))
 
     def _setfile(self, filename, length, offset):
         """Use file as source of bits."""
@@ -1499,7 +1499,7 @@ class Bits(object):
                 val <<= 8 * chunksize
                 val += struct.unpack('<L', bytes(self._datastore.getbyteslice(endbyte + 1 - chunksize, endbyte + 1)))[0]
                 endbyte -= chunksize
-            for b in xrange(endbyte, startbyte - 1, -1):
+            for b in range(endbyte, startbyte - 1, -1):
                 val <<= 8
                 val += self._datastore.getbyte(b)
         else:
@@ -1832,7 +1832,7 @@ class Bits(object):
                            if len(binstring) < boundary else binstring
         try:
             bytelist = [int(padded_binstring[x:x + 8], 2)
-                        for x in xrange(0, len(padded_binstring), 8)]
+                        for x in range(0, len(padded_binstring), 8)]
         except ValueError:
             raise CreationError("Invalid character in bin initialiser {0}.", binstring)
         self._setbytes_unsafe(bytearray(bytelist), length, 0)
@@ -1905,7 +1905,7 @@ class Bits(object):
                 data = bytearray.fromhex(hexstring)
             except TypeError:
                 # Python 2.6 needs a unicode string (a bug). 2.7 and 3.x work fine.
-                data = bytearray.fromhex(unicode(hexstring))
+                data = bytearray.fromhex(str(hexstring))
         except ValueError:
             raise CreationError("Invalid symbol in hex initialiser.")
         self._setbytes_unsafe(data, length * 4, 0)
@@ -1956,7 +1956,7 @@ class Bits(object):
         try:
             return cache[(bs, offset)]
         except KeyError:
-            if isinstance(bs, basestring):
+            if isinstance(bs, str):
                 b = cls()
                 try:
                     _, tokens = tokenparser(bs)
@@ -1999,14 +1999,14 @@ class Bits(object):
         """Reads a token from the bitstring and returns the result."""
         if length is not None and int(length) > self.length - pos:
             raise ReadError("Reading off the end of the data. "
-                            "Tried to read {0} bits when only {1} available.".format(int(length), self.length - pos))
+                            "Tried to read {} bits when only {} available.".format(int(length), self.length - pos))
         try:
             val = name_to_read[name](self, length, pos)
             return val, pos + length
         except KeyError:
             if name == 'pad':
                 return None, pos + length
-            raise ValueError("Can't parse token {0}:{1}".format(name, length))
+            raise ValueError("Can't parse token {}:{}".format(name, length))
         except TypeError:
             # This is for the 'ue', 'se' and 'bool' tokens. They will also return the new pos.
             return name_to_read[name](self, pos)
@@ -2169,7 +2169,7 @@ class Bits(object):
         """Invert every bit."""
         set = self._datastore.setbyte
         get = self._datastore.getbyte
-        for p in xrange(self._datastore.byteoffset, self._datastore.byteoffset + self._datastore.bytelength):
+        for p in range(self._datastore.byteoffset, self._datastore.byteoffset + self._datastore.bytelength):
             set(p, 256 + ~get(p))
 
     def _ilshift(self, n):
@@ -2212,7 +2212,7 @@ class Bits(object):
                 self._datastore = offsetcopy(self._datastore, bs_bitoffset)
         a = self._datastore.rawbytes
         b = bs._datastore.rawbytes
-        for i in xrange(len(a)):
+        for i in range(len(a)):
             a[i] = f(a[i + self_byteoffset], b[i + bs_byteoffset])
         return self
 
@@ -2267,13 +2267,13 @@ class Bits(object):
     def _readlist(self, fmt, pos, **kwargs):
         tokens = []
         stretchy_token = None
-        if isinstance(fmt, basestring):
+        if isinstance(fmt, str):
             fmt = [fmt]
         # Not very optimal this, but replace integers with 'bits' tokens
         # TODO: optimise
         for i, f in enumerate(fmt):
             if isinstance(f, numbers.Integral):
-                fmt[i] = "bits:{0}".format(f)
+                fmt[i] = "bits:{}".format(f)
         for f_item in fmt:
             stretchy, tkns = tokenparser(f_item, tuple(sorted(kwargs.keys())))
             if stretchy:
@@ -2720,12 +2720,12 @@ class Bits(object):
         value = bool(value)
         length = self.len
         if pos is None:
-            pos = xrange(self.len)
+            pos = range(self.len)
         for p in pos:
             if p < 0:
                 p += length
             if not 0 <= p < length:
-                raise IndexError("Bit position {0} out of range.".format(p))
+                raise IndexError("Bit position {} out of range.".format(p))
             if not self._datastore.getbit(p) is value:
                 return False
         return True
@@ -2742,12 +2742,12 @@ class Bits(object):
         value = bool(value)
         length = self.len
         if pos is None:
-            pos = xrange(self.len)
+            pos = range(self.len)
         for p in pos:
             if p < 0:
                 p += length
             if not 0 <= p < length:
-                raise IndexError("Bit position {0} out of range.".format(p))
+                raise IndexError("Bit position {} out of range.".format(p))
             if self._datastore.getbit(p) is value:
                 return True
         return False
@@ -2766,7 +2766,7 @@ class Bits(object):
             return 0
         # count the number of 1s (from which it's easy to work out the 0s).
         # Don't count the final byte yet.
-        count = sum(BIT_COUNT[self._datastore.getbyte(i)] for i in xrange(self._datastore.bytelength - 1))
+        count = sum(BIT_COUNT[self._datastore.getbyte(i)] for i in range(self._datastore.bytelength - 1))
         # adjust for bits at start that aren't part of the bitstring
         if self._offset:
             count -= BIT_COUNT[self._datastore.getbyte(0) >> (8 - self._offset)]
@@ -3043,7 +3043,7 @@ class BitArray(Bits):
             self._ensureinmemory()
 
     def __new__(cls, auto=None, length=None, offset=None, **kwargs):
-        x = super(BitArray, cls).__new__(cls)
+        x = super().__new__(cls)
         y = Bits.__new__(BitArray, auto, length, offset, **kwargs)
         x._datastore = y._datastore
         return x
@@ -3104,7 +3104,7 @@ class BitArray(Bits):
                 if value in (1, -1):
                     self._set(key)
                     return
-                raise ValueError("Cannot set a single bit with integer {0}.".format(value))
+                raise ValueError("Cannot set a single bit with integer {}.".format(value))
             value = Bits(value)
             if value.len == 1:
                 # TODO: this can't be optimal
@@ -3134,7 +3134,7 @@ class BitArray(Bits):
                     value = Bits(value)
                 except TypeError:
                     raise TypeError("Bitstring, integer or string expected. "
-                                    "Got {0}.".format(type(value)))
+                                    "Got {}.".format(type(value)))
             if key.start is not None:
                 start = key.start
                 if key.start < 0:
@@ -3458,21 +3458,21 @@ class BitArray(Bits):
         """
         f = self._set if value else self._unset
         if pos is None:
-            pos = xrange(self.len)
+            pos = range(self.len)
         try:
             length = self.len
             for p in pos:
                 if p < 0:
                     p += length
                 if not 0 <= p < length:
-                    raise IndexError("Bit position {0} out of range.".format(p))
+                    raise IndexError("Bit position {} out of range.".format(p))
                 f(p)
         except TypeError:
             # Single pos
             if pos < 0:
                 pos += self.len
             if not 0 <= pos < length:
-                raise IndexError("Bit position {0} out of range.".format(pos))
+                raise IndexError("Bit position {} out of range.".format(pos))
             f(pos)
 
     def invert(self, pos=None):
@@ -3487,7 +3487,7 @@ class BitArray(Bits):
         if pos is None:
             self._invert_all()
             return
-        if not isinstance(pos, collections.Iterable):
+        if not isinstance(pos, collections.abc.Iterable):
             pos = (pos,)
         length = self.len
 
@@ -3495,7 +3495,7 @@ class BitArray(Bits):
             if p < 0:
                 p += length
             if not 0 <= p < length:
-                raise IndexError("Bit position {0} out of range.".format(p))
+                raise IndexError("Bit position {} out of range.".format(p))
             self._invert(p)
 
     def ror(self, bits, start=None, end=None):
@@ -3560,12 +3560,12 @@ class BitArray(Bits):
             bytesizes = [(end - start) // 8]
         elif isinstance(fmt, numbers.Integral):
             if fmt < 0:
-                raise ValueError("Improper byte length {0}.".format(fmt))
+                raise ValueError("Improper byte length {}.".format(fmt))
             bytesizes = [fmt]
-        elif isinstance(fmt, basestring):
+        elif isinstance(fmt, str):
             m = STRUCT_PACK_RE.match(fmt)
             if not m:
-                raise ValueError("Cannot parse format string {0}.".format(fmt))
+                raise ValueError("Cannot parse format string {}.".format(fmt))
             # Split the format string into a list of 'q', '4h' etc.
             formatlist = re.findall(STRUCT_SPLIT_RE, m.group('fmt'))
             # Now deal with multiplicative factors, 4h -> hhhh etc.
@@ -3575,11 +3575,11 @@ class BitArray(Bits):
                     bytesizes.append(PACK_CODE_SIZE[f])
                 else:
                     bytesizes.extend([PACK_CODE_SIZE[f[-1]]] * int(f[:-1]))
-        elif isinstance(fmt, collections.Iterable):
+        elif isinstance(fmt, collections.abc.Iterable):
             bytesizes = fmt
             for bytesize in bytesizes:
                 if not isinstance(bytesize, numbers.Integral) or bytesize < 0:
-                    raise ValueError("Improper byte length {0}.".format(bytesize))
+                    raise ValueError("Improper byte length {}.".format(bytesize))
         else:
             raise TypeError("Format must be an integer, string or iterable.")
 
@@ -3593,7 +3593,7 @@ class BitArray(Bits):
         else:
             # Just try one (set of) byteswap(s).
             finalbit = start + totalbitsize
-        for patternend in xrange(start + totalbitsize, finalbit + 1, totalbitsize):
+        for patternend in range(start + totalbitsize, finalbit + 1, totalbitsize):
             bytestart = patternend - totalbitsize
             for bytesize in bytesizes:
                 byteend = bytestart + bytesize * 8
@@ -3781,7 +3781,7 @@ class ConstBitStream(Bits):
         self._pos = 0
 
     def __new__(cls, auto=None, length=None, offset=None, **kwargs):
-        x = super(ConstBitStream, cls).__new__(cls)
+        x = super().__new__(cls)
         x._initialise(auto, length, offset, **kwargs)
         return x
 
@@ -3880,7 +3880,7 @@ class ConstBitStream(Bits):
         _, token = tokenparser(fmt)
         if len(token) != 1:
             self._pos = p
-            raise ValueError("Format string should be a single token, not {0} "
+            raise ValueError("Format string should be a single token, not {} "
                              "tokens - use readlist() instead.".format(len(token)))
         name, length, _ = token[0]
         if length is None:
@@ -4121,7 +4121,7 @@ class BitStream(ConstBitStream, BitArray):
             self._ensureinmemory()
 
     def __new__(cls, auto=None, length=None, offset=None, **kwargs):
-        x = super(BitStream, cls).__new__(cls)
+        x = super().__new__(cls)
         x._initialise(auto, length, offset, **kwargs)
         return x
 
@@ -4186,7 +4186,7 @@ def pack(fmt, *values, **kwargs):
 
     """
     tokens = []
-    if isinstance(fmt, basestring):
+    if isinstance(fmt, str):
         fmt = [fmt]
     try:
         for f_item in fmt:
diff --git a/python/bitstring/test/test_bitarray.py b/python/bitstring/test/test_bitarray.py
index b80f90617b..9436f84620 100644
--- a/python/bitstring/test/test_bitarray.py
+++ b/python/bitstring/test/test_bitarray.py
@@ -255,7 +255,7 @@ class SliceAssignment(unittest.TestCase):
             self.assertTrue(False)
         except ValueError:
             pass
-        class A(object): pass
+        class A: pass
         try:
             a[1:2] = A()
             self.assertTrue(False)
diff --git a/python/bitstring/test/test_bitstream.py b/python/bitstring/test/test_bitstream.py
index f94193d324..4ddd5b1779 100644
--- a/python/bitstring/test/test_bitstream.py
+++ b/python/bitstring/test/test_bitstream.py
@@ -757,7 +757,7 @@ class FromFile(unittest.TestCase):
         # and so this test won't work for anyone except me!
         try:
             s = ConstBitStream(filename='11GB.mkv')
-        except IOError:
+        except OSError:
             return
         self.assertEqual(s.len, 11743020505 * 8)
         self.assertEqual(s[1000000000:1000000100].hex, 'bdef7335d4545f680d669ce24')
@@ -1529,7 +1529,7 @@ class Adding(unittest.TestCase):
         s5 = BitStream(bytes=b'\xff', offset=2, length=3)
         s6 = BitStream('0b111')
         self.assertTrue(s5 == s6)
-        class A(object):
+        class A:
             pass
         self.assertFalse(s5 == A())
 
@@ -2493,7 +2493,7 @@ class Split(unittest.TestCase):
         s = pack('<2h', 1, 2)
         a, b = s.unpack('<2h')
         self.assertEqual((a, b), (1, 2))
-        s = pack('<100q', *range(100))
+        s = pack('<100q', *list(range(100)))
         self.assertEqual(s.len, 100 * 64)
         self.assertEqual(s[44*64:45*64].uintle, 44)
         s = pack('@L0B2h', 5, 5, 5)
@@ -2812,7 +2812,7 @@ class Split(unittest.TestCase):
         b = ConstBitStream('0x2')
         c = ConstBitStream('0x1')
         c.pos = 3
-        s = set((a, b, c))
+        s = {a, b, c}
         self.assertEqual(len(s), 2)
         self.assertEqual(hash(a), hash(c))
 
@@ -2875,9 +2875,9 @@ class Set(unittest.TestCase):
 
     def testSetList(self):
         a = BitStream(length=18)
-        a.set(True, range(18))
+        a.set(True, list(range(18)))
         self.assertEqual(a.int, -1)
-        a.set(False, range(18))
+        a.set(False, list(range(18)))
         self.assertEqual(a.int, 0)
 
     def testUnset(self):
@@ -2907,7 +2907,7 @@ class Set(unittest.TestCase):
 class Invert(unittest.TestCase):
     def testInvertBits(self):
         a = BitStream('0b111000')
-        a.invert(range(a.len))
+        a.invert(list(range(a.len)))
         self.assertEqual(a, '0b000111')
         a.invert([0, 1, -1])
         self.assertEqual(a, '0b110110')
@@ -3456,8 +3456,8 @@ class Bugs(unittest.TestCase):
         self.assertEqual(s.len, 17)
 
     def testInitFromIterable(self):
-        self.assertTrue(isinstance(range(10), collections.Iterable))
-        s = ConstBitStream(range(12))
+        self.assertTrue(isinstance(list(range(10)), collections.abc.Iterable))
+        s = ConstBitStream(list(range(12)))
         self.assertEqual(s, '0x7ff')
 
     def testFunctionNegativeIndices(self):
@@ -3554,7 +3554,7 @@ class Bugs(unittest.TestCase):
         self.assertRaises(ValueError, a.rol, 5, start=-4, end=-6)
 
     def testByteSwapInt(self):
-        s = pack('5*uintle:16', *range(10, 15))
+        s = pack('5*uintle:16', *list(range(10, 15)))
         self.assertEqual(list(range(10, 15)), s.unpack('5*uintle:16'))
         swaps = s.byteswap(2)
         self.assertEqual(list(range(10, 15)), s.unpack('5*uintbe:16'))
@@ -3588,7 +3588,7 @@ class Bugs(unittest.TestCase):
 
     def testByteSwapIterable(self):
         s = BitStream('0x0011223344556677')
-        swaps = s.byteswap(range(1, 4), repeat=False)
+        swaps = s.byteswap(list(range(1, 4)), repeat=False)
         self.assertEqual(swaps, 1)
         self.assertEqual(s, '0x0022115544336677')
         swaps = s.byteswap([2], start=8)
@@ -3628,7 +3628,7 @@ class Bugs(unittest.TestCase):
     def testBracketTokens(self):
         s = BitStream('3*(0x0, 0b1)')
         self.assertEqual(s, '0x0, 0b1, 0x0, 0b1, 0x0, 0b1')
-        s = pack('2*(uint:12, 3*(7, 6))', *range(3, 17))
+        s = pack('2*(uint:12, 3*(7, 6))', *list(range(3, 17)))
         a = s.unpack('12, 7, 6, 7, 6, 7, 6, 12, 7, 6, 7, 6, 7, 6')
         self.assertEqual(a, list(range(3, 17)))
         b = s.unpack('2*(12,3*(7,6))')
diff --git a/python/blessings/blessings/__init__.py b/python/blessings/blessings/__init__.py
index 081288ba68..e5e71e3654 100644
--- a/python/blessings/blessings/__init__.py
+++ b/python/blessings/blessings/__init__.py
@@ -25,7 +25,7 @@ if ('3', '0', '0') <= python_version_tuple() < ('3', '2', '2+'):  # Good till 3.
 __all__ = ['Terminal']
 
 
-class Terminal(object):
+class Terminal:
     """An abstraction around terminal capabilities
 
     Unlike curses, this doesn't require clearing the screen before doing
@@ -189,7 +189,7 @@ class Terminal(object):
         for descriptor in self._init_descriptor, sys.__stdout__:
             try:
                 return struct.unpack('hhhh', ioctl(descriptor, TIOCGWINSZ, '\000' * 8))[0:2]
-            except IOError:
+            except OSError:
                 pass
         return None, None  # Should never get here
 
@@ -201,9 +201,9 @@ class Terminal(object):
 
             term = Terminal()
             with term.location(2, 5):
-                print 'Hello, world!'
+                print('Hello, world!')
                 for x in xrange(10):
-                    print 'I can do it %i times!' % x
+                    print('I can do it %i times!' % x)
 
         Specify ``x`` to move to a certain column, ``y`` to move to a certain
         row, or both.
@@ -272,7 +272,7 @@ class Terminal(object):
                 # optimization: combine all formatting into a single escape
                 # sequence.
                 return self._formatting_string(
-                    u''.join(self._resolve_formatter(s) for s in formatters))
+                    ''.join(self._resolve_formatter(s) for s in formatters))
             else:
                 return ParametrizingString(self._resolve_capability(attr))
 
@@ -289,7 +289,7 @@ class Terminal(object):
             # contain chars > 127, and UTF-8 never changes anything within that
             # range..
             return code.decode('utf-8')
-        return u''
+        return ''
 
     def _resolve_color(self, color):
         """Resolve a color like red or on_bright_green into a callable capability."""
@@ -326,14 +326,14 @@ def derivative_colors(colors):
                [('on_bright_' + c) for c in colors])
 
 
-COLORS = set(['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'])
+COLORS = {'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'}
 COLORS.update(derivative_colors(COLORS))
 COMPOUNDABLES = (COLORS |
-                 set(['bold', 'underline', 'reverse', 'blink', 'dim', 'italic',
-                      'shadow', 'standout', 'subscript', 'superscript']))
+                 {'bold', 'underline', 'reverse', 'blink', 'dim', 'italic',
+                      'shadow', 'standout', 'subscript', 'superscript'})
 
 
-class ParametrizingString(unicode):
+class ParametrizingString(str):
     """A Unicode string which can be called to parametrize it as a terminal capability"""
     def __new__(cls, formatting, normal=None):
         """Instantiate.
@@ -343,7 +343,7 @@ class ParametrizingString(unicode):
             "normal" capability.
 
         """
-        new = unicode.__new__(cls, formatting)
+        new = str.__new__(cls, formatting)
         new._normal = normal
         return new
 
@@ -360,11 +360,11 @@ class ParametrizingString(unicode):
             # running simply `nosetests` (without progressive) on nose-
             # progressive. Perhaps the terminal has gone away between calling
             # tigetstr and calling tparm.
-            return u''
+            return ''
         except TypeError:
             # If the first non-int (i.e. incorrect) arg was a string, suggest
             # something intelligent:
-            if len(args) == 1 and isinstance(args[0], basestring):
+            if len(args) == 1 and isinstance(args[0], str):
                 raise TypeError(
                     'A native or nonexistent capability template received '
                     '%r when it was expecting ints. You probably misspelled a '
@@ -375,10 +375,10 @@ class ParametrizingString(unicode):
                 raise
 
 
-class FormattingString(unicode):
+class FormattingString(str):
     """A Unicode string which can be called upon a piece of text to wrap it in formatting"""
     def __new__(cls, formatting, normal):
-        new = unicode.__new__(cls, formatting)
+        new = str.__new__(cls, formatting)
         new._normal = normal
         return new
 
@@ -393,7 +393,7 @@ class FormattingString(unicode):
         return self + text + self._normal
 
 
-class NullCallableString(unicode):
+class NullCallableString(str):
     """A dummy class to stand in for ``FormattingString`` and ``ParametrizingString``
 
     A callable bytestring that returns an empty Unicode when called with an int
@@ -402,12 +402,12 @@ class NullCallableString(unicode):
 
     """
     def __new__(cls):
-        new = unicode.__new__(cls, u'')
+        new = str.__new__(cls, '')
         return new
 
     def __call__(self, arg):
         if isinstance(arg, int):
-            return u''
+            return ''
         return arg  # TODO: Force even strs in Python 2.x to be unicodes? Nah. How would I know what encoding to use to convert it?
 
 
@@ -429,7 +429,7 @@ def split_into_formatters(compound):
     return merged_segs
 
 
-class Location(object):
+class Location:
     """Context manager for temporarily moving the cursor"""
     def __init__(self, term, x=None, y=None):
         self.x, self.y = x, y
diff --git a/python/blessings/blessings/tests.py b/python/blessings/blessings/tests.py
index a02a3924a8..09b05559f8 100644
--- a/python/blessings/blessings/tests.py
+++ b/python/blessings/blessings/tests.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 """Automated tests (as opposed to human-verified test patterns)
 
 It was tempting to mock out curses to get predictable output from ``tigetstr``,
@@ -52,8 +51,8 @@ def test_capability():
 def test_capability_without_tty():
     """Assert capability templates are '' when stream is not a tty."""
     t = TestTerminal(stream=StringIO())
-    eq_(t.save, u'')
-    eq_(t.red, u'')
+    eq_(t.save, '')
+    eq_(t.red, '')
 
 
 def test_capability_with_forced_tty():
@@ -84,11 +83,11 @@ def test_location():
     t = TestTerminal(stream=StringIO(), force_styling=True)
 
     with t.location(3, 4):
-        t.stream.write(u'hi')
+        t.stream.write('hi')
 
     eq_(t.stream.getvalue(), unicode_cap('sc') +
                              unicode_parm('cup', 4, 3) +
-                             u'hi' +
+                             'hi' +
                              unicode_cap('rc'))
 
 
@@ -111,7 +110,7 @@ def test_null_fileno():
     out = StringIO()
     out.fileno = None
     t = TestTerminal(stream=out)
-    eq_(t.save, u'')
+    eq_(t.save, '')
 
 
 def test_mnemonic_colors():
@@ -179,26 +178,26 @@ def test_formatting_functions():
     """Test crazy-ass formatting wrappers, both simple and compound."""
     t = TestTerminal()
     # By now, it should be safe to use sugared attributes. Other tests test those.
-    eq_(t.bold(u'hi'), t.bold + u'hi' + t.normal)
-    eq_(t.green('hi'), t.green + u'hi' + t.normal)  # Plain strs for Python 2.x
+    eq_(t.bold('hi'), t.bold + 'hi' + t.normal)
+    eq_(t.green('hi'), t.green + 'hi' + t.normal)  # Plain strs for Python 2.x
     # Test some non-ASCII chars, probably not necessary:
-    eq_(t.bold_green(u'boö'), t.bold + t.green + u'boö' + t.normal)
+    eq_(t.bold_green('boö'), t.bold + t.green + 'boö' + t.normal)
     eq_(t.bold_underline_green_on_red('boo'),
-        t.bold + t.underline + t.green + t.on_red + u'boo' + t.normal)
+        t.bold + t.underline + t.green + t.on_red + 'boo' + t.normal)
     # Don't spell things like this:
     eq_(t.on_bright_red_bold_bright_green_underline('meh'),
-        t.on_bright_red + t.bold + t.bright_green + t.underline + u'meh' + t.normal)
+        t.on_bright_red + t.bold + t.bright_green + t.underline + 'meh' + t.normal)
 
 
 def test_formatting_functions_without_tty():
     """Test crazy-ass formatting wrappers when there's no tty."""
     t = TestTerminal(stream=StringIO())
-    eq_(t.bold(u'hi'), u'hi')
-    eq_(t.green('hi'), u'hi')
+    eq_(t.bold('hi'), 'hi')
+    eq_(t.green('hi'), 'hi')
     # Test non-ASCII chars, no longer really necessary:
-    eq_(t.bold_green(u'boö'), u'boö')
-    eq_(t.bold_underline_green_on_red('loo'), u'loo')
-    eq_(t.on_bright_red_bold_bright_green_underline('meh'), u'meh')
+    eq_(t.bold_green('boö'), 'boö')
+    eq_(t.bold_underline_green_on_red('loo'), 'loo')
+    eq_(t.on_bright_red_bold_bright_green_underline('meh'), 'meh')
 
 
 def test_nice_formatting_errors():
@@ -206,22 +205,22 @@ def test_nice_formatting_errors():
     t = TestTerminal()
     try:
         t.bold_misspelled('hey')
-    except TypeError, e:
+    except TypeError as e:
         assert 'probably misspelled' in e.args[0]
 
     try:
-        t.bold_misspelled(u'hey')  # unicode
-    except TypeError, e:
+        t.bold_misspelled('hey')  # unicode
+    except TypeError as e:
         assert 'probably misspelled' in e.args[0]
 
     try:
         t.bold_misspelled(None)  # an arbitrary non-string
-    except TypeError, e:
+    except TypeError as e:
         assert 'probably misspelled' not in e.args[0]
 
     try:
         t.bold_misspelled('a', 'b')  # >1 string arg
-    except TypeError, e:
+    except TypeError as e:
         assert 'probably misspelled' not in e.args[0]
 
 
diff --git a/python/blessings/setup.py b/python/blessings/setup.py
index 6af55452d8..57f3d4cf8d 100644
--- a/python/blessings/setup.py
+++ b/python/blessings/setup.py
@@ -4,8 +4,7 @@ from setuptools import setup, find_packages
 
 
 extra_setup = {}
-if sys.version_info >= (3,):
-    extra_setup['use_2to3'] = True
+extra_setup['use_2to3'] = True
 
 setup(
     name='blessings',
diff --git a/python/compare-locales/compare_locales/checks.py b/python/compare-locales/compare_locales/checks.py
index 0faffcc698..654d335ebd 100644
--- a/python/compare-locales/compare_locales/checks.py
+++ b/python/compare-locales/compare_locales/checks.py
@@ -44,7 +44,7 @@ class PrintfException(Exception):
 class PropertiesChecker(Checker):
     '''Tests to run on .properties files.
     '''
-    pattern = re.compile('.*\.properties$')
+    pattern = re.compile(r'.*\.properties$')
     printf = re.compile(r'%(?P<good>%|'
                         r'(?:(?P<number>[1-9][0-9]*)\$)?'
                         r'(?P<width>\*|[0-9]+)?'
@@ -95,7 +95,7 @@ class PropertiesChecker(Checker):
     def checkPrintf(self, refSpecs, l10nValue):
         try:
             l10nSpecs = self.getPrintfSpecs(l10nValue)
-        except PrintfException, e:
+        except PrintfException as e:
             yield ('error', e.pos, e.msg, 'printf')
             return
         if refSpecs != l10nSpecs:
@@ -112,20 +112,20 @@ class PropertiesChecker(Checker):
                         # trailing specs missing, that's just a warning
                         warn = ', '.join('trailing argument %d `%s` missing' %
                                          (i+1, refSpecs[i])
-                                         for i in xrange(i1, i2))
+                                         for i in range(i1, i2))
                     else:
-                        for i in xrange(i1, i2):
+                        for i in range(i1, i2):
                             msgs.append('argument %d `%s` missing' %
                                         (i+1, refSpecs[i]))
                     continue
                 if action == 'insert':
                     # obsolete argument in l10n
-                    for i in xrange(j1, j2):
+                    for i in range(j1, j2):
                         msgs.append('argument %d `%s` obsolete' %
                                     (i+1, l10nSpecs[i]))
                     continue
                 if action == 'replace':
-                    for i, j in zip(xrange(i1, i2), xrange(j1, j2)):
+                    for i, j in zip(range(i1, i2), range(j1, j2)):
                         msgs.append('argument %d `%s` should be `%s`' %
                                     (j+1, l10nSpecs[j], refSpecs[i]))
             if msgs:
@@ -183,7 +183,7 @@ class DTDChecker(Checker):
 
     Also checks for some CSS and number heuristics in the values.
     """
-    pattern = re.compile('.*\.dtd$')
+    pattern = re.compile(r'.*\.dtd$')
 
     eref = re.compile('&(%s);' % DTDParser.Name)
     tmpl = '''<!DOCTYPE elem [%s]>
@@ -253,7 +253,7 @@ class DTDChecker(Checker):
             parser.parse(StringIO(self.tmpl %
                                   (refEnt.all.encode('utf-8') + entities,
                                    '&%s;' % refEnt.key.encode('utf-8'))))
-        except sax.SAXParseException, e:
+        except sax.SAXParseException as e:
             yield ('warning',
                    (0, 0),
                    "can't parse en-US value", 'xmlparse')
@@ -275,7 +275,7 @@ class DTDChecker(Checker):
             parser.parse(StringIO(self.tmpl % (
                 l10nEnt.all.encode('utf-8') + _entities,
                 '&%s;' % l10nEnt.key.encode('utf-8'))))
-        except sax.SAXParseException, e:
+        except sax.SAXParseException as e:
             # xml parse error, yield error
             # sometimes, the error is reported on our fake closing
             # element, make that the end of the last line
@@ -293,7 +293,7 @@ class DTDChecker(Checker):
                     col -= len("<!DOCTYPE elem [")  # first line is DOCTYPE
             yield ('error', (lnr, col), ' '.join(e.args), 'xmlparse')
 
-        warntmpl = u'Referencing unknown entity `%s`'
+        warntmpl = 'Referencing unknown entity `%s`'
         if reflist:
             if inContext:
                 elsewhere = reflist - inContext
@@ -342,7 +342,7 @@ class DTDChecker(Checker):
                         if u != ru:
                             msgs.append("units for %s don't match "
                                         "(%s != %s)" % (s, u, ru))
-                for s in refMap.iterkeys():
+                for s in refMap.keys():
                     msgs.insert(0, '%s only in reference' % s)
                 if msgs:
                     yield ('warning', 0, ', '.join(msgs), 'css')
diff --git a/python/compare-locales/compare_locales/commands.py b/python/compare-locales/compare_locales/commands.py
index 61b58ec4b2..f60c979f36 100644
--- a/python/compare-locales/compare_locales/commands.py
+++ b/python/compare-locales/compare_locales/commands.py
@@ -4,6 +4,7 @@
 
 'Commands exposed to commandlines'
 
+from __future__ import print_function
 import logging
 from optparse import OptionParser, make_option
 
@@ -66,7 +67,7 @@ data in a json useful for Exhibit
         logging.getLogger().setLevel(logging.WARNING -
                                      (options.v - options.q)*10)
         observer = self.handle(args, options)
-        print observer.serialize(type=options.data).encode('utf-8', 'replace')
+        print((observer.serialize(type=options.data).encode('utf-8', 'replace')))
 
     def handle(self, args, options):
         """Subclasses need to implement this method for the actual
@@ -109,8 +110,8 @@ Be careful to specify the right merge directory when using this option."""),
         try:
             observer = compareApp(app, merge_stage=options.merge,
                                   clobber=options.clobber)
-        except (OSError, IOError), exc:
-            print "FAIL: " + str(exc)
+        except (OSError, IOError) as exc:
+            print(("FAIL: " + str(exc)))
             self.parser.exit(2)
         return observer
 
diff --git a/python/compare-locales/compare_locales/compare.py b/python/compare-locales/compare_locales/compare.py
index 4f71c46f8f..d0006ef50f 100644
--- a/python/compare-locales/compare_locales/compare.py
+++ b/python/compare-locales/compare_locales/compare.py
@@ -4,6 +4,7 @@
 
 'Mozilla l10n compare locales tool'
 
+from __future__ import print_function
 import codecs
 import os
 import os.path
@@ -42,7 +43,7 @@ class Tree(object):
         old = None
         new = tuple(parts)
         t = self
-        for k, v in self.branches.iteritems():
+        for k, v in self.branches.items():
             for i, part in enumerate(zip(k, parts)):
                 if part[0] != part[1]:
                     i -= 1
@@ -79,7 +80,7 @@ class Tree(object):
         If flag is 'value', key_or_value is a value object, otherwise
         (flag is 'key') it's a key string.
         '''
-        keys = self.branches.keys()
+        keys = list(self.branches.keys())
         keys.sort()
         if self.value is not None:
             yield (depth, 'value', self.value)
@@ -94,7 +95,7 @@ class Tree(object):
         Only the values need to take care that they're JSON-able.
         '''
         json = {}
-        keys = self.branches.keys()
+        keys = list(self.branches.keys())
         keys.sort()
         if self.value is not None:
             json['value'] = self.value
@@ -110,7 +111,7 @@ class Tree(object):
                 return self.indent * t[0] + '/'.join(t[2])
             return self.indent * (t[0] + 1) + str(t[2])
 
-        return map(tostr, self.getContent())
+        return list(map(tostr, self.getContent()))
 
     def __str__(self):
         return '\n'.join(self.getStrRows())
@@ -164,18 +165,18 @@ class DirectoryCompare(SequenceMatcher):
         self.set_seq2([i for i in other])
         for tag, i1, i2, j1, j2 in self.get_opcodes():
             if tag == 'equal':
-                for i, j in zip(xrange(i1, i2), xrange(j1, j2)):
+                for i, j in zip(range(i1, i2), range(j1, j2)):
                     self.watcher.compare(self.a[i], self.b[j])
             elif tag == 'delete':
-                for i in xrange(i1, i2):
+                for i in range(i1, i2):
                     self.watcher.add(self.a[i], other.cloneFile(self.a[i]))
             elif tag == 'insert':
-                for j in xrange(j1, j2):
+                for j in range(j1, j2):
                     self.watcher.remove(self.b[j])
             else:
-                for j in xrange(j1, j2):
+                for j in range(j1, j2):
                     self.watcher.remove(self.b[j])
-                for i in xrange(i1, i2):
+                for i in range(i1, i2):
                     self.watcher.add(self.a[i], other.cloneFile(self.a[i]))
 
 
@@ -203,14 +204,14 @@ class Observer(object):
 
         self.summary = defaultdict(intdict)
         if 'summary' in state:
-            for loc, stats in state['summary'].iteritems():
+            for loc, stats in state['summary'].items():
                 self.summary[loc].update(stats)
         self.details = state['details']
         self.filter = None
 
     def getSummary(self):
         plaindict = {}
-        for k, v in self.summary.iteritems():
+        for k, v in self.summary.items():
             plaindict[k] = dict(v)
         return plaindict
 
@@ -261,7 +262,7 @@ class Observer(object):
 
     def toExhibit(self):
         items = []
-        for locale in sorted(self.summary.iterkeys()):
+        for locale in sorted(self.summary.keys()):
             summary = self.summary[locale]
             if locale is not None:
                 item = {'id': 'xxx/' + locale,
@@ -339,10 +340,10 @@ class Observer(object):
             return '\n'.join(o)
 
         out = []
-        for locale, summary in sorted(self.summary.iteritems()):
+        for locale, summary in sorted(self.summary.items()):
             if locale is not None:
                 out.append(locale + ':')
-            out += [k + ': ' + str(v) for k, v in sorted(summary.iteritems())]
+            out += [k + ': ' + str(v) for k, v in sorted(summary.items())]
             total = sum([summary[k]
                          for k in ['changed', 'unchanged', 'report', 'missing',
                                    'missingInFiles']
@@ -352,7 +353,7 @@ class Observer(object):
                 rate = (('changed' in summary and summary['changed'] * 100) or
                         0) / total
             out.append('%d%% of entries changed' % rate)
-        return '\n'.join(map(tostr, self.details.getContent()) + out)
+        return '\n'.join(list(map(tostr, self.details.getContent())) + out)
 
     def __str__(self):
         return 'observer'
@@ -391,7 +392,7 @@ class ContentComparer:
             os.makedirs(outdir)
         if not p.canMerge:
             shutil.copyfile(ref_file.fullpath, outfile)
-            print "copied reference to " + outfile
+            print(("copied reference to " + outfile))
             return
         if skips:
             # skips come in ordered by key name, we need them in file order
@@ -412,7 +413,7 @@ class ContentComparer:
         else:
             shutil.copyfile(l10n_file.fullpath, outfile)
             f = codecs.open(outfile, 'ab', p.encoding)
-        print "adding to " + outfile
+        print(("adding to " + outfile))
 
         def ensureNewline(s):
             if not s.endswith('\n'):
@@ -448,17 +449,17 @@ class ContentComparer:
             # we didn't parse this before
             try:
                 p.readContents(ref_file.getContents())
-            except Exception, e:
+            except Exception as e:
                 self.notify('error', ref_file, str(e))
                 return
             self.reference[ref_file] = p.parse()
         ref = self.reference[ref_file]
-        ref_list = ref[1].keys()
+        ref_list = list(ref[1].keys())
         ref_list.sort()
         try:
             p.readContents(l10n.getContents())
             l10n_entities, l10n_map = p.parse()
-        except Exception, e:
+        except Exception as e:
             self.notify('error', l10n, str(e))
             return
         lines = []
@@ -468,12 +469,12 @@ class ContentComparer:
                 lines.append(0)
                 for m in self.nl.finditer(p.contents):
                     lines.append(m.end())
-            for i in xrange(len(lines), 0, -1):
+            for i in range(len(lines), 0, -1):
                 if offset >= lines[i - 1]:
                     return (i, offset - lines[i - 1])
             return (1, offset)
 
-        l10n_list = l10n_map.keys()
+        l10n_list = list(l10n_map.keys())
         l10n_list.sort()
         ar = AddRemove()
         ar.set_left(ref_list)
@@ -542,7 +543,7 @@ class ContentComparer:
                         if tp == 'error' and self.merge_stage is not None:
                             skips.append(l10nent)
                         self.notify(tp, l10n,
-                                    u"%s at line %d, column %d for %s" %
+                                    "%s at line %d, column %d for %s" %
                                     (msg, _l, col, refent.key))
                 pass
         if missing:
@@ -573,7 +574,7 @@ class ContentComparer:
         try:
             p.readContents(f.getContents())
             entities, map = p.parse()
-        except Exception, e:
+        except Exception as e:
             self.notify('error', f, str(e))
             return
         self.notify('missingInFiles', missing, len(map))
@@ -615,7 +616,7 @@ def compareApp(app, other_observer=None, merge_stage=None, clobber=False):
                     clobberdir = os.path.join(locale_merge, module)
                     if os.path.exists(clobberdir):
                         shutil.rmtree(clobberdir)
-                        print "clobbered " + clobberdir
+                        print(("clobbered " + clobberdir))
             dir_comp.compareWith(localization)
     return comparer.observer
 
diff --git a/python/compare-locales/compare_locales/parser.py b/python/compare-locales/compare_locales/parser.py
index a97cf201be..cfbc5a925d 100644
--- a/python/compare-locales/compare_locales/parser.py
+++ b/python/compare-locales/compare_locales/parser.py
@@ -122,10 +122,10 @@ class Parser:
         f = codecs.open(file, 'r', self.encoding)
         try:
             self.contents = f.read()
-        except UnicodeDecodeError, e:
+        except UnicodeDecodeError as e:
             (logging.getLogger('locales')
                     .error("Can't read file: " + file + '; ' + str(e)))
-            self.contents = u''
+            self.contents = ''
         f.close()
 
     def readContents(self, contents):
@@ -219,31 +219,31 @@ class DTDParser(Parser):
     # | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] |
     # [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] |
     # [#x10000-#xEFFFF]
-    CharMinusDash = u'\x09\x0A\x0D\u0020-\u002C\u002E-\uD7FF\uE000-\uFFFD'
+    CharMinusDash = '\x09\x0A\x0D\u0020-\u002C\u002E-\uD7FF\uE000-\uFFFD'
     XmlComment = '<!--(?:-?[%s])*?-->' % CharMinusDash
-    NameStartChar = u':A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF' + \
-        u'\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F' + \
-        u'\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD'
+    NameStartChar = ':A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF' + \
+        '\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F' + \
+        '\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD'
     # + \U00010000-\U000EFFFF seems to be unsupported in python
 
     # NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 |
     #     [#x0300-#x036F] | [#x203F-#x2040]
-    NameChar = NameStartChar + ur'\-\.0-9' + u'\xB7\u0300-\u036F\u203F-\u2040'
+    NameChar = NameStartChar + urr'\-\.0-9' + '\xB7\u0300-\u036F\u203F-\u2040'
     Name = '[' + NameStartChar + '][' + NameChar + ']*'
-    reKey = re.compile('(?:(?P<pre>\s*)(?P<precomment>(?:' + XmlComment +
-                       '\s*)*)(?P<entity><!ENTITY\s+(?P<key>' + Name +
-                       ')\s+(?P<val>\"[^\"]*\"|\'[^\']*\'?)\s*>)'
-                       '(?P<post>[ \t]*(?:' + XmlComment + '\s*)*\n?)?)',
+    reKey = re.compile(r'(?:(?P<pre>\s*)(?P<precomment>(?:' + XmlComment +
+                       r'\s*)*)(?P<entity><!ENTITY\s+(?P<key>' + Name +
+                       ')\\s+(?P<val>\"[^\"]*\"|\'[^\']*\'?)\\s*>)'
+                       '(?P<post>[ \t]*(?:' + XmlComment + '\\s*)*\n?)?)',
                        re.DOTALL)
     # add BOM to DTDs, details in bug 435002
-    reHeader = re.compile(u'^\ufeff?'
-                          u'(\s*<!--.*(http://mozilla.org/MPL/2.0/|'
-                          u'LICENSE BLOCK)([^-]+-)*[^-]+-->)?', re.S)
-    reFooter = re.compile('\s*(<!--([^-]+-)*[^-]+-->\s*)*$')
-    rePE = re.compile('(?:(\s*)((?:' + XmlComment + '\s*)*)'
-                      '(<!ENTITY\s+%\s+(' + Name +
-                      ')\s+SYSTEM\s+(\"[^\"]*\"|\'[^\']*\')\s*>\s*%' + Name +
-                      ';)([ \t]*(?:' + XmlComment + '\s*)*\n?)?)')
+    reHeader = re.compile('^\ufeff?'
+                          r'(\s*<!--.*(http://mozilla.org/MPL/2.0/|'
+                          'LICENSE BLOCK)([^-]+-)*[^-]+-->)?', re.S)
+    reFooter = re.compile(r'\s*(<!--([^-]+-)*[^-]+-->\s*)*$')
+    rePE = re.compile(r'(?:(\s*)((?:' + XmlComment + r'\s*)*)'
+                      r'(<!ENTITY\s+%\s+(' + Name +
+                      ')\\s+SYSTEM\\s+(\"[^\"]*\"|\'[^\']*\')\\s*>\\s*%' + Name +
+                      ';)([ \t]*(?:' + XmlComment + '\\s*)*\n?)?)')
 
     def getEntity(self, contents, offset):
         '''
@@ -273,15 +273,15 @@ class DTDParser(Parser):
 
 class PropertiesParser(Parser):
     escape = re.compile(r'\\((?P<uni>u[0-9a-fA-F]{1,4})|'
-                        '(?P<nl>\n\s*)|(?P<single>.))', re.M)
+                        '(?P<nl>\n\\s*)|(?P<single>.))', re.M)
     known_escapes = {'n': '\n', 'r': '\r', 't': '\t', '\\': '\\'}
 
     def __init__(self):
-        self.reKey = re.compile('^(\s*)'
-                                '((?:[#!].*?\n\s*)*)'
-                                '([^#!\s\n][^=:\n]*?)\s*[:=][ \t]*', re.M)
-        self.reHeader = re.compile('^\s*([#!].*\s*)+')
-        self.reFooter = re.compile('\s*([#!].*\s*)*$')
+        self.reKey = re.compile(r'^(\s*)'
+                                '((?:[#!].*?\n\\s*)*)'
+                                '([^#!\\s\n][^=:\n]*?)\\s*[:=][ \t]*', re.M)
+        self.reHeader = re.compile(r'^\s*([#!].*\s*)+')
+        self.reFooter = re.compile(r'\s*([#!].*\s*)*$')
         self._escapedEnd = re.compile(r'\\+$')
         self._trailingWS = re.compile(r'[ \t]*$')
         Parser.__init__(self)
@@ -354,11 +354,11 @@ class DefinesParser(Parser):
     canMerge = False
 
     def __init__(self):
-        self.reKey = re.compile('^(\s*)((?:^#(?!define\s).*\s*)*)'
-                                '(#define[ \t]+(\w+)[ \t]+(.*?))([ \t]*$\n?)',
+        self.reKey = re.compile(r'^(\s*)((?:^#(?!define\s).*\s*)*)'
+                                '(#define[ \t]+(\\w+)[ \t]+(.*?))([ \t]*$\n?)',
                                 re.M)
-        self.reHeader = re.compile('^\s*(#(?!define\s).*\s*)*')
-        self.reFooter = re.compile('\s*(#(?!define\s).*\s*)*$', re.M)
+        self.reHeader = re.compile(r'^\s*(#(?!define\s).*\s*)*')
+        self.reFooter = re.compile(r'\s*(#(?!define\s).*\s*)*$', re.M)
         Parser.__init__(self)
 
 
@@ -373,9 +373,9 @@ class IniParser(Parser):
     ...
     '''
     def __init__(self):
-        self.reHeader = re.compile('^((?:\s*|[;#].*)\n)*\[.+?\]\n', re.M)
-        self.reKey = re.compile('(\s*)((?:[;#].*\n\s*)*)((.+?)=(.*))(\n?)')
-        self.reFooter = re.compile('\s*([;#].*\s*)*$')
+        self.reHeader = re.compile('^((?:\\s*|[;#].*)\n)*\\[.+?\\]\n', re.M)
+        self.reKey = re.compile('(\\s*)((?:[;#].*\n\\s*)*)((.+?)=(.*))(\n?)')
+        self.reFooter = re.compile(r'\s*([;#].*\s*)*$')
         Parser.__init__(self)
 
 
diff --git a/python/compare-locales/compare_locales/paths.py b/python/compare-locales/compare_locales/paths.py
index f72b3a2e72..0ee4eb36c9 100644
--- a/python/compare-locales/compare_locales/paths.py
+++ b/python/compare-locales/compare_locales/paths.py
@@ -4,15 +4,15 @@
 
 import os.path
 import os
-from ConfigParser import ConfigParser, NoSectionError, NoOptionError
-from urlparse import urlparse, urljoin
-from urllib import pathname2url, url2pathname
-from urllib2 import urlopen
+from configparser import ConfigParser, NoSectionError, NoOptionError
+from urllib.parse import urlparse, urljoin
+from urllib.request import pathname2url, url2pathname
+from urllib.request import urlopen
 from collections import defaultdict
 from compare_locales import util
 
 
-class L10nConfigParser(object):
+class L10nConfigParser:
     '''Helper class to gather application information from ini files.
 
     This class is working on synchronous open to read files or web data.
@@ -58,7 +58,7 @@ class L10nConfigParser(object):
         filterurl = urljoin(self.inipath, 'filter.py')
         try:
             l = {}
-            execfile(url2pathname(urlparse(filterurl).path), {}, l)
+            exec(compile(open(url2pathname(urlparse(filterurl).path), "rb").read(), url2pathname(urlparse(filterurl).path), 'exec'), {}, l)
             if 'test' in l and callable(l['test']):
                 filters = [l['test']]
             else:
@@ -151,11 +151,9 @@ class L10nConfigParser(object):
         """Iterate over all dirs and base paths for this l10n.ini as well
         as the included ones.
         """
-        for t in self.dirsIter():
-            yield t
+        yield from self.dirsIter()
         for child in self.children:
-            for t in child.directories():
-                yield t
+            yield from child.directories()
 
     def allLocales(self):
         """Return a list of all the locales of this project"""
@@ -214,7 +212,7 @@ class SourceTreeConfigParser(L10nConfigParser):
         return (basepath, )
 
 
-class File(object):
+class File:
 
     def __init__(self, fullpath, file, module=None, locale=None):
         self.fullpath = fullpath
@@ -225,7 +223,7 @@ class File(object):
 
     def getContents(self):
         # open with universal line ending support and read
-        return open(self.fullpath, 'rU').read()
+        return open(self.fullpath).read()
 
     def __hash__(self):
         f = self.file
@@ -245,7 +243,7 @@ class File(object):
         return cmp(self.file, other.file)
 
 
-class EnumerateDir(object):
+class EnumerateDir:
     ignore_dirs = ['CVS', '.svn', '.hg', '.git']
 
     def __init__(self, basepath, module='', locale=None, ignore_subdirs=[]):
@@ -287,7 +285,7 @@ class EnumerateDir(object):
                            self.module, self.locale)
 
 
-class LocalesWrap(object):
+class LocalesWrap:
 
     def __init__(self, base, module, locales, ignore_subdirs=[]):
         self.base = base
@@ -302,7 +300,7 @@ class LocalesWrap(object):
                                         self.ignore_subdirs))
 
 
-class EnumerateApp(object):
+class EnumerateApp:
     reference = 'en-US'
 
     def __init__(self, inipath, l10nbase, locales=None):
@@ -355,7 +353,7 @@ class EnumerateApp(object):
         code and an directory enumerator will be given.
         '''
         dirmap = dict(self.config.directories())
-        mods = dirmap.keys()
+        mods = list(dirmap.keys())
         mods.sort()
         for mod in mods:
             if self.reference == 'en-US':
diff --git a/python/compare-locales/compare_locales/tests/__init__.py b/python/compare-locales/compare_locales/tests/__init__.py
index 8808d78f4c..458a14bc10 100644
--- a/python/compare-locales/compare_locales/tests/__init__.py
+++ b/python/compare-locales/compare_locales/tests/__init__.py
@@ -5,11 +5,12 @@
 '''Mixins for parser tests.
 '''
 
-from itertools import izip_longest
+
 from pkg_resources import resource_string
 import re
 
 from compare_locales.parser import getParser
+from itertools import zip_longest
 
 
 class ParserTestMixin():
@@ -39,7 +40,7 @@ class ParserTestMixin():
         '''
         self.parser.readContents(content)
         entities = [entity for entity in self.parser]
-        for entity, ref in izip_longest(entities, refs):
+        for entity, ref in zip_longest(entities, refs):
             self.assertTrue(entity, 'excess reference entity')
             self.assertTrue(ref, 'excess parsed entity')
             self.assertEqual(entity.val, ref[1])
diff --git a/python/compare-locales/compare_locales/tests/test_checks.py b/python/compare-locales/compare_locales/tests/test_checks.py
index b995d43f90..0b43f2ddb9 100644
--- a/python/compare-locales/compare_locales/tests/test_checks.py
+++ b/python/compare-locales/compare_locales/tests/test_checks.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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/.
@@ -111,9 +110,9 @@ class TestDTDs(BaseHelper):
                    (('warning', (0, 0), 'Referencing unknown entity `not`',
                      'xmlparse'),))
         # make sure we only handle translated entity references
-        self._test(u'''<!ENTITY foo "This is &ƞǿŧ; good">
+        self._test('''<!ENTITY foo "This is &ƞǿŧ; good">
 '''.encode('utf-8'),
-            (('warning', (0, 0), u'Referencing unknown entity `ƞǿŧ`',
+            (('warning', (0, 0), 'Referencing unknown entity `ƞǿŧ`',
               'xmlparse'),))
 
     def testErrorFirstLine(self):
@@ -233,10 +232,10 @@ class TestAndroid(unittest.TestCase):
     Make sure we're hitting our extra rules only if
     we're passing in a DTD file in the embedding/android module.
     """
-    apos_msg = u"Apostrophes in Android DTDs need escaping with \\' or " + \
-               u"\\u0027, or use \u2019, or put string in quotes."
-    quot_msg = u"Quotes in Android DTDs need escaping with \\\" or " + \
-               u"\\u0022, or put string in apostrophes."
+    apos_msg = "Apostrophes in Android DTDs need escaping with \\' or " + \
+               "\\u0027, or use \u2019, or put string in quotes."
+    quot_msg = "Quotes in Android DTDs need escaping with \\\" or " + \
+               "\\u0022, or put string in apostrophes."
 
     def getEntity(self, v):
         return Entity(v, lambda s: s, (0, len(v)), (), (0, 0), (), (),
@@ -267,7 +266,7 @@ class TestAndroid(unittest.TestCase):
                          (('warning', (0, 0),
                            'Referencing unknown entity `ref`', 'xmlparse'),))
         # no report on stray ampersand or quote, if not completely quoted
-        for i in xrange(3):
+        for i in range(3):
             # make sure we're catching unescaped apostrophes,
             # try 0..5 backticks
             l10n = self.getDTDEntity("\\"*(2*i) + "'")
@@ -323,7 +322,7 @@ class TestAndroid(unittest.TestCase):
                          (('error', 12, 'truncated \\uXXXX escape',
                            'android'),))
         # broken unicode escape, try to set the error off
-        l10n = self.getDTDEntity(u"\u9690"*14+"\u006"+"  "+"\u0064")
+        l10n = self.getDTDEntity("\u9690"*14+"\u006"+"  "+"\u0064")
         self.assertEqual(tuple(checker.check(ref, l10n)),
                          (('error', 14, 'truncated \\uXXXX escape',
                            'android'),))
diff --git a/python/compare-locales/compare_locales/tests/test_dtd.py b/python/compare-locales/compare_locales/tests/test_dtd.py
index 87ddcde301..cc8a642c88 100644
--- a/python/compare-locales/compare_locales/tests/test_dtd.py
+++ b/python/compare-locales/compare_locales/tests/test_dtd.py
@@ -47,7 +47,7 @@ class TestDTD(ParserTestMixin, unittest.TestCase):
             return qr.sub(lambda m: m.group(0) == '"' and "'" or '"', s)
 
         self._test(quot2apos(self.quoteContent),
-                   map(lambda t: (t[0], quot2apos(t[1])), self.quoteRef))
+                   [(t[0], quot2apos(t[1])) for t in self.quoteRef])
 
     def test_parsed_ref(self):
         self._test('''<!ENTITY % fooDTD SYSTEM "chrome://brand.dtd">
@@ -70,7 +70,7 @@ class TestDTD(ParserTestMixin, unittest.TestCase):
         for e in p:
             self.assertEqual(e.key, 'foo')
             self.assertEqual(e.val, 'value')
-        self.assert_('MPL' in p.header)
+        self.assertTrue('MPL' in p.header)
         p.readContents('''\
 <!-- 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,
@@ -80,7 +80,7 @@ class TestDTD(ParserTestMixin, unittest.TestCase):
         for e in p:
             self.assertEqual(e.key, 'foo')
             self.assertEqual(e.val, 'value')
-        self.assert_('MPL' in p.header)
+        self.assertTrue('MPL' in p.header)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/python/compare-locales/compare_locales/tests/test_ini.py b/python/compare-locales/compare_locales/tests/test_ini.py
index 4c8cc03e15..d057c2860f 100644
--- a/python/compare-locales/compare_locales/tests/test_ini.py
+++ b/python/compare-locales/compare_locales/tests/test_ini.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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/.
@@ -24,7 +23,7 @@ class TestIniParser(ParserTestMixin, unittest.TestCase):
 [Strings]
 TitleText=Some Title
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('UTF-8' in self.parser.header)
+        self.assertTrue('UTF-8' in self.parser.header)
 
     def testMPL2_Space_UTF(self):
         self._test(mpl2 + '''
@@ -32,14 +31,14 @@ TitleText=Some Title
 [Strings]
 TitleText=Some Title
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def testMPL2_Space(self):
         self._test(mpl2 + '''
 [Strings]
 TitleText=Some Title
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def testMPL2_MultiSpace(self):
         self._test(mpl2 + '''\
@@ -49,7 +48,7 @@ TitleText=Some Title
 [Strings]
 TitleText=Some Title
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def testMPL2_JunkBeforeCategory(self):
         self._test(mpl2 + '''\
@@ -59,7 +58,7 @@ TitleText=Some Title
 ''', (('_junk_\\d+_0-213$', mpl2 + '''\
 Junk
 [Strings]'''), ('TitleText', 'Some Title')))
-        self.assert_('MPL' not in self.parser.header)
+        self.assertTrue('MPL' not in self.parser.header)
 
     def test_TrailingComment(self):
         self._test(mpl2 + '''
@@ -67,7 +66,7 @@ Junk
 TitleText=Some Title
 ;Stray trailing comment
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def test_SpacedTrailingComments(self):
         self._test(mpl2 + '''
@@ -78,7 +77,7 @@ TitleText=Some Title
 ;Second stray comment
 
 ''', (('TitleText', 'Some Title'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def test_TrailingCommentsAndJunk(self):
         self._test(mpl2 + '''
@@ -96,7 +95,7 @@ Junk
 ;Second stray comment
 
 ''')))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def test_JunkInbetweenEntries(self):
         self._test(mpl2 + '''
@@ -109,7 +108,7 @@ Good=other string
 ''', (('TitleText', 'Some Title'), ('_junk_\\d+_231-236$', '''\
 
 Junk'''), ('Good', 'other string')))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/python/compare-locales/compare_locales/tests/test_merge.py b/python/compare-locales/compare_locales/tests/test_merge.py
index c006edbb5d..c87457943a 100644
--- a/python/compare-locales/compare_locales/tests/test_merge.py
+++ b/python/compare-locales/compare_locales/tests/test_merge.py
@@ -12,7 +12,7 @@ from compare_locales.paths import File
 from compare_locales.compare import ContentComparer
 
 
-class ContentMixin(object):
+class ContentMixin:
     maxDiff = None  # we got big dictionaries to compare
     extension = None  # OVERLOAD
 
@@ -58,7 +58,7 @@ eff = lEff
              'details': {}
              }
         )
-        self.assert_(not os.path.exists(os.path.join(cc.merge_stage,
+        self.assertTrue(not os.path.exists(os.path.join(cc.merge_stage,
                                                      'l10n.properties')))
 
     def testMissing(self):
@@ -81,7 +81,7 @@ eff = effVal""")
              'details': {
                  'children': [
                      ('l10n.properties',
-                         {'value': {'missingEntity': [u'eff', u'foo']}}
+                         {'value': {'missingEntity': ['eff', 'foo']}}
                       )
                  ]}
              }
@@ -91,7 +91,7 @@ eff = effVal""")
         p = getParser(mergefile)
         p.readFile(mergefile)
         [m, n] = p.parse()
-        self.assertEqual(map(lambda e: e.key,  m), ["bar", "eff", "foo"])
+        self.assertEqual([e.key for e in m], ["bar", "eff", "foo"])
 
     def testError(self):
         self.assertTrue(os.path.isdir(self.tmp))
@@ -115,9 +115,9 @@ eff = leffVal
                  'children': [
                      ('l10n.properties',
                          {'value': {
-                          'error': [u'argument 1 `S` should be `d` '
-                                    u'at line 1, column 6 for bar'],
-                          'missingEntity': [u'foo']}}
+                          'error': ['argument 1 `S` should be `d` '
+                                    'at line 1, column 6 for bar'],
+                          'missingEntity': ['foo']}}
                       )
                  ]}
              }
@@ -151,7 +151,7 @@ eff = leffVal
              'details': {
                  'children': [
                      ('l10n.properties',
-                         {'value': {'obsoleteEntity': [u'other']}})]},
+                         {'value': {'obsoleteEntity': ['other']}})]},
              }
         )
 
@@ -189,7 +189,7 @@ class TestDTD(unittest.TestCase, ContentMixin):
              'details': {}
              }
         )
-        self.assert_(
+        self.assertTrue(
             not os.path.exists(os.path.join(cc.merge_stage, 'l10n.dtd')))
 
     def testMissing(self):
@@ -212,7 +212,7 @@ class TestDTD(unittest.TestCase, ContentMixin):
              'details': {
                  'children': [
                      ('l10n.dtd',
-                         {'value': {'missingEntity': [u'eff', u'foo']}}
+                         {'value': {'missingEntity': ['eff', 'foo']}}
                       )
                  ]}
              }
@@ -222,7 +222,7 @@ class TestDTD(unittest.TestCase, ContentMixin):
         p = getParser(mergefile)
         p.readFile(mergefile)
         [m, n] = p.parse()
-        self.assertEqual(map(lambda e: e.key,  m), ["bar", "eff", "foo"])
+        self.assertEqual([e.key for e in m], ["bar", "eff", "foo"])
 
     def testJunk(self):
         self.assertTrue(os.path.isdir(self.tmp))
@@ -247,9 +247,9 @@ class TestDTD(unittest.TestCase, ContentMixin):
                  'children': [
                      ('l10n.dtd',
                          {'value': {
-                             'error': [u'Unparsed content "<!ENTY bar '
-                                       u'\'gimmick\'>" at 23-44'],
-                             'missingEntity': [u'bar']}}
+                             'error': ['Unparsed content "<!ENTY bar '
+                                       '\'gimmick\'>" at 23-44'],
+                             'missingEntity': ['bar']}}
                       )
                  ]}
              }
@@ -259,7 +259,7 @@ class TestDTD(unittest.TestCase, ContentMixin):
         p = getParser(mergefile)
         p.readFile(mergefile)
         [m, n] = p.parse()
-        self.assertEqual(map(lambda e: e.key,  m), ["foo", "eff", "bar"])
+        self.assertEqual([e.key for e in m], ["foo", "eff", "bar"])
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/python/compare-locales/compare_locales/tests/test_properties.py b/python/compare-locales/compare_locales/tests/test_properties.py
index 331a1a57c7..ad3ec0638a 100644
--- a/python/compare-locales/compare_locales/tests/test_properties.py
+++ b/python/compare-locales/compare_locales/tests/test_properties.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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/.
@@ -22,8 +21,8 @@ two_lines_triple = This line is one of two and ends in \\\
 and still has another line coming
 ''', (
             ('one_line', 'This is one line'),
-            ('two_line', u'This is the first of two lines'),
-            ('one_line_trailing', u'This line ends in \\'),
+            ('two_line', 'This is the first of two lines'),
+            ('one_line_trailing', 'This line ends in \\'),
             ('_junk_\\d+_113-126$', 'and has junk\n'),
             ('two_lines_triple', 'This line is one of two and ends in \\'
              'and still has another line coming')))
@@ -41,11 +40,11 @@ and still has another line coming
     def test_bug121341(self):
         # port of xpcom/tests/unit/test_bug121341.js
         self.parser.readContents(self.resource('bug121341.properties'))
-        ref = ['abc', 'xy', u"\u1234\t\r\n\u00AB\u0001\n",
+        ref = ['abc', 'xy', "\u1234\t\r\n\u00AB\u0001\n",
                "this is multiline property",
-               "this is another multiline property", u"test\u0036",
-               "yet another multiline propery", u"\ttest5\u0020", " test6\t",
-               u"c\uCDEFd", u"\uABCD"]
+               "this is another multiline property", "test\u0036",
+               "yet another multiline propery", "\ttest5\u0020", " test6\t",
+               "c\uCDEFd", "\uABCD"]
         i = iter(self.parser)
         for r, e in zip(ref, i):
             self.assertEqual(e.val, r)
@@ -64,7 +63,7 @@ and an end''', (('bar', 'one line with a # part that looks like a comment '
 
 foo=value
 ''', (('foo', 'value'),))
-        self.assert_('MPL' in self.parser.header)
+        self.assertTrue('MPL' in self.parser.header)
 
     def test_escapes(self):
         self.parser.readContents(r'''
diff --git a/python/compare-locales/compare_locales/tests/test_util.py b/python/compare-locales/compare_locales/tests/test_util.py
index fd2d2c92ba..badf6c5c26 100644
--- a/python/compare-locales/compare_locales/tests/test_util.py
+++ b/python/compare-locales/compare_locales/tests/test_util.py
@@ -9,19 +9,19 @@ from compare_locales import util
 
 class ParseLocalesTest(unittest.TestCase):
     def test_empty(self):
-        self.assertEquals(util.parseLocales(''), [])
+        self.assertEqual(util.parseLocales(''), [])
 
     def test_all(self):
-        self.assertEquals(util.parseLocales('''af
+        self.assertEqual(util.parseLocales('''af
 de'''), ['af', 'de'])
 
     def test_shipped(self):
-        self.assertEquals(util.parseLocales('''af
+        self.assertEqual(util.parseLocales('''af
 ja win mac
 de'''), ['af', 'de', 'ja'])
 
     def test_sparse(self):
-        self.assertEquals(util.parseLocales('''
+        self.assertEqual(util.parseLocales('''
 af
 
 de
diff --git a/python/compare-locales/compare_locales/tests/test_webapps.py b/python/compare-locales/compare_locales/tests/test_webapps.py
index 2f12236490..cfb3cfed6f 100644
--- a/python/compare-locales/compare_locales/tests/test_webapps.py
+++ b/python/compare-locales/compare_locales/tests/test_webapps.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # 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/.
@@ -22,7 +21,7 @@ class TestFileComparison(unittest.TestCase):
         filecomp = self.mock_FileComparison(_listdir)
         filecomp.files()
         self.assertEqual(filecomp.locales(), [])
-        self.assertEqual(filecomp._reference.keys(), ['my_app'])
+        self.assertEqual(list(filecomp._reference.keys()), ['my_app'])
         file_ = filecomp._reference['my_app']
         self.assertEqual(file_.file, 'locales/my_app.en-US.properties')
 
@@ -36,6 +35,6 @@ class TestFileComparison(unittest.TestCase):
         filecomp.files()
         self.assertEqual(filecomp.locales(),
                          ['ar', 'sr-Latn', 'sv-SE'])
-        self.assertEqual(filecomp._files['ar'].keys(), ['my_app'])
+        self.assertEqual(list(filecomp._files['ar'].keys()), ['my_app'])
         file_ = filecomp._files['ar']['my_app']
         self.assertEqual(file_.file, 'locales/my_app.ar.properties')
diff --git a/python/compare-locales/compare_locales/webapps.py b/python/compare-locales/compare_locales/webapps.py
index 42f5b56578..4181668255 100644
--- a/python/compare-locales/compare_locales/webapps.py
+++ b/python/compare-locales/compare_locales/webapps.py
@@ -80,7 +80,7 @@ class Manifest(object):
     def load_and_parse(self):
         try:
             manifest = json.load(open(self.file.fullpath))
-        except (ValueError, IOError), e:
+        except (ValueError, IOError) as e:
             if self.watcher:
                 self.watcher.notify('error', self.file, str(e))
             return False
@@ -96,11 +96,11 @@ class Manifest(object):
         rv = defaultdict(dict)
         localizable = manifest_fragment.pop('locales', {})
         if localizable:
-            for locale, keyvalue in localizable.iteritems():
-                for key, value in keyvalue.iteritems():
+            for locale, keyvalue in localizable.items():
+                for key, value in keyvalue.items():
                     key = '.'.join(['locales', 'AB_CD', key])
                     rv[locale][key] = value
-        for key, sub_manifest in manifest_fragment.iteritems():
+        for key, sub_manifest in manifest_fragment.items():
             if not isinstance(sub_manifest, dict):
                 continue
             subdict = self.extract_manifest_strings(sub_manifest)
@@ -108,7 +108,7 @@ class Manifest(object):
                 for locale, keyvalue in subdict:
                     rv[locale].update((key + '.' + subkey, value)
                                       for subkey, value
-                                      in keyvalue.iteritems())
+                                      in keyvalue.items())
         return rv
 
     def compare(self, locales):
@@ -166,7 +166,7 @@ class FileComparison(object):
         '''Get the locales present in the webapp
         '''
         self.files()
-        locales = self._files.keys()
+        locales = list(self._files.keys())
         locales.sort()
         return locales
 
diff --git a/python/compare-locales/mach_commands.py b/python/compare-locales/mach_commands.py
index 7be6a50e75..ad287185a8 100644
--- a/python/compare-locales/mach_commands.py
+++ b/python/compare-locales/mach_commands.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
@@ -78,4 +78,4 @@ class CompareLocales(MachCommandBase):
         app = EnumerateApp(l10n_ini, l10n_base, locales)
         observer = compareApp(app, merge_stage=merge_dir,
                               clobber=True)
-        print(observer.serialize())
+        print((observer.serialize()))
diff --git a/python/configobj/configobj.py b/python/configobj/configobj.py
index c1f6e6df86..1135cbd2cd 100644
--- a/python/configobj/configobj.py
+++ b/python/configobj/configobj.py
@@ -161,7 +161,7 @@ class Builder(object):
         return m(o)
     
     def build_List(self, o):
-        return map(self.build, o.getChildren())
+        return list(map(self.build, o.getChildren()))
     
     def build_Const(self, o):
         return o.value
@@ -170,7 +170,7 @@ class Builder(object):
         d = {}
         i = iter(map(self.build, o.getChildren()))
         for el in i:
-            d[el] = i.next()
+            d[el] = next(i)
         return d
     
     def build_Tuple(self, o):
@@ -188,7 +188,7 @@ class Builder(object):
         raise UnknownType('Undefined Name')
     
     def build_Add(self, o):
-        real, imag = map(self.build_Const, o.getChildren())
+        real, imag = list(map(self.build_Const, o.getChildren()))
         try:
             real = float(real)
         except TypeError:
@@ -518,7 +518,7 @@ class Section(dict):
         self._initialise()
         # we do this explicitly so that __setitem__ is used properly
         # (rather than just passing to ``dict.__init__``)
-        for entry, value in indict.iteritems():
+        for entry, value in indict.items():
             self[entry] = value
             
             
@@ -566,11 +566,11 @@ class Section(dict):
         """Fetch the item and do string interpolation."""
         val = dict.__getitem__(self, key)
         if self.main.interpolation: 
-            if isinstance(val, basestring):
+            if isinstance(val, str):
                 return self._interpolate(key, val)
             if isinstance(val, list):
                 def _check(entry):
-                    if isinstance(entry, basestring):
+                    if isinstance(entry, str):
                         return self._interpolate(key, entry)
                     return entry
                 new = [_check(entry) for entry in val]
@@ -593,7 +593,7 @@ class Section(dict):
         ``unrepr`` must be set when setting a value to a dictionary, without
         creating a new sub-section.
         """
-        if not isinstance(key, basestring):
+        if not isinstance(key, str):
             raise ValueError('The key "%s" is not a string.' % key)
         
         # add the comment
@@ -627,11 +627,11 @@ class Section(dict):
             if key not in self:
                 self.scalars.append(key)
             if not self.main.stringify:
-                if isinstance(value, basestring):
+                if isinstance(value, str):
                     pass
                 elif isinstance(value, (list, tuple)):
                     for entry in value:
-                        if not isinstance(entry, basestring):
+                        if not isinstance(entry, str):
                             raise TypeError('Value is not a string "%s".' % entry)
                 else:
                     raise TypeError('Value is not a string "%s".' % value)
@@ -721,7 +721,7 @@ class Section(dict):
 
     def items(self):
         """D.items() -> list of D's (key, value) pairs, as 2-tuples"""
-        return zip((self.scalars + self.sections), self.values())
+        return list(zip((self.scalars + self.sections), list(self.values())))
 
 
     def keys(self):
@@ -741,7 +741,7 @@ class Section(dict):
 
     def iterkeys(self):
         """D.iterkeys() -> an iterator over the keys of D"""
-        return iter((self.scalars + self.sections))
+        return iter(self.scalars + self.sections)
 
     __iter__ = iterkeys
 
@@ -972,7 +972,7 @@ class Section(dict):
             return False
         else:
             try:
-                if not isinstance(val, basestring):
+                if not isinstance(val, str):
                     # TODO: Why do we raise a KeyError here?
                     raise KeyError()
                 else:
@@ -1243,7 +1243,7 @@ class ConfigObj(Section):
         
         
     def _load(self, infile, configspec):
-        if isinstance(infile, basestring):
+        if isinstance(infile, str):
             self.filename = infile
             if os.path.isfile(infile):
                 h = open(infile, 'rb')
@@ -1453,6 +1453,11 @@ class ConfigObj(Section):
             return self._decode(infile, self.encoding)
         
         # No encoding specified - so we need to check for UTF8/UTF16
+        if not isinstance(line, bytes):
+            # Already decoded text (Python 3); no BOM to check
+            if isinstance(infile, (list, tuple)):
+                return infile
+            return infile.splitlines(True)
         for BOM, (encoding, final_encoding) in BOMS.items():
             if not line.startswith(BOM):
                 continue
@@ -1469,7 +1474,7 @@ class ConfigObj(Section):
                     else:
                         infile = newline
                     # UTF8 - don't decode
-                    if isinstance(infile, basestring):
+                    if isinstance(infile, str):
                         return infile.splitlines(True)
                     else:
                         return infile
@@ -1477,7 +1482,7 @@ class ConfigObj(Section):
                 return self._decode(infile, encoding)
             
         # No BOM discovered and no encoding specified, just return
-        if isinstance(infile, basestring):
+        if isinstance(infile, str):
             # infile read from a file will be a single string
             return infile.splitlines(True)
         return infile
@@ -1497,12 +1502,12 @@ class ConfigObj(Section):
         
         if is a string, it also needs converting to a list.
         """
-        if isinstance(infile, basestring):
+        if isinstance(infile, str):
             # can't be unicode
             # NOTE: Could raise a ``UnicodeDecodeError``
             return infile.decode(encoding).splitlines(True)
         for i, line in enumerate(infile):
-            if not isinstance(line, unicode):
+            if not isinstance(line, str):
                 # NOTE: The isinstance test here handles mixed lists of unicode/string
                 # NOTE: But the decode will break on any non-string values
                 # NOTE: Or could raise a ``UnicodeDecodeError``
@@ -1524,7 +1529,7 @@ class ConfigObj(Section):
         Used by ``stringify`` within validate, to turn non-string values
         into strings.
         """
-        if not isinstance(value, basestring):
+        if not isinstance(value, str):
             return str(value)
         else:
             return value
@@ -1641,7 +1646,7 @@ class ConfigObj(Section):
                             comment = ''
                             try:
                                 value = unrepr(value)
-                            except Exception, e:
+                            except Exception as e:
                                 if type(e) == UnknownType:
                                     msg = 'Unknown name or type in value at line %s.'
                                 else:
@@ -1654,7 +1659,7 @@ class ConfigObj(Section):
                         comment = ''
                         try:
                             value = unrepr(value)
-                        except Exception, e:
+                        except Exception as e:
                             if isinstance(e, UnknownType):
                                 msg = 'Unknown name or type in value at line %s.'
                             else:
@@ -1777,7 +1782,7 @@ class ConfigObj(Section):
                 return self._quote(value[0], multiline=False) + ','
             return ', '.join([self._quote(val, multiline=False)
                 for val in value])
-        if not isinstance(value, basestring):
+        if not isinstance(value, str):
             if self.stringify:
                 value = str(value)
             else:
@@ -1929,11 +1934,11 @@ class ConfigObj(Section):
                                        raise_errors=True,
                                        file_error=True,
                                        _inspec=True)
-            except ConfigObjError, e:
+            except ConfigObjError as e:
                 # FIXME: Should these errors have a reference
                 #        to the already parsed ConfigObj ?
                 raise ConfigspecError('Parsing configspec failed: %s' % e)
-            except IOError, e:
+            except IOError as e:
                 raise IOError('Reading configspec failed: %s' % e)
         
         self.configspec = configspec
@@ -2189,7 +2194,7 @@ class ConfigObj(Section):
                                         val,
                                         missing=missing
                                         )
-            except validator.baseErrorClass, e:
+            except validator.baseErrorClass as e:
                 if not preserve_errors or isinstance(e, self._vdtMissingValue):
                     out[entry] = False
                 else:
@@ -2338,7 +2343,7 @@ class ConfigObj(Section):
         This method raises a ``ReloadError`` if the ConfigObj doesn't have
         a filename attribute pointing to a file.
         """
-        if not isinstance(self.filename, basestring):
+        if not isinstance(self.filename, str):
             raise ReloadError()
 
         filename = self.filename
diff --git a/python/configobj/validate.py b/python/configobj/validate.py
index 73dbdb891b..ee3a55dff3 100644
--- a/python/configobj/validate.py
+++ b/python/configobj/validate.py
@@ -284,7 +284,7 @@ def dottedQuadToNum(ip):
     except socket.error:
         # bug in inet_aton, corrected in Python 2.4
         if ip.strip() == '255.255.255.255':
-            return 0xFFFFFFFFL
+            return 0xFFFFFFFF
         else:
             raise ValueError('Not a good dotted-quad IP: %s' % ip)
     return
@@ -316,11 +316,11 @@ def numToDottedQuad(num):
     import socket, struct
     
     # no need to intercept here, 4294967295L is fine
-    if num > 4294967295L or num < 0:
+    if num > 4294967295 or num < 0:
         raise ValueError('Not a good numeric IP: %s' % num)
     try:
         return socket.inet_ntoa(
-            struct.pack('!L', long(num)))
+            struct.pack('!L', int(num)))
     except (socket.error, struct.error, OverflowError):
         raise ValueError('Not a good numeric IP: %s' % num)
 
@@ -736,10 +736,10 @@ def _is_num_param(names, values, to_float=False):
     for (name, val) in zip(names, values):
         if val is None:
             out_params.append(val)
-        elif isinstance(val, (int, long, float, basestring)):
+        elif isinstance(val, (int, int, float, str)):
             try:
                 out_params.append(fun(val))
-            except ValueError, e:
+            except ValueError as e:
                 raise VdtParamError(name, val)
         else:
             raise VdtParamError(name, val)
@@ -793,9 +793,9 @@ def is_integer(value, min=None, max=None):
     0
     """
     (min_val, max_val) = _is_num_param(('min', 'max'), (min, max))
-    if not isinstance(value, (int, long, basestring)):
+    if not isinstance(value, (int, int, str)):
         raise VdtTypeError(value)
-    if isinstance(value, basestring):
+    if isinstance(value, str):
         # if it's a string - does it represent an integer ?
         try:
             value = int(value)
@@ -845,7 +845,7 @@ def is_float(value, min=None, max=None):
     """
     (min_val, max_val) = _is_num_param(
         ('min', 'max'), (min, max), to_float=True)
-    if not isinstance(value, (int, long, float, basestring)):
+    if not isinstance(value, (int, int, float, str)):
         raise VdtTypeError(value)
     if not isinstance(value, float):
         # if it's a string - does it represent a float ?
@@ -910,7 +910,7 @@ def is_boolean(value):
     VdtTypeError: the value "up" is of the wrong type.
     
     """
-    if isinstance(value, basestring):
+    if isinstance(value, str):
         try:
             return bool_dict[value.lower()]
         except KeyError:
@@ -953,7 +953,7 @@ def is_ip_addr(value):
     Traceback (most recent call last):
     VdtTypeError: the value "0" is of the wrong type.
     """
-    if not isinstance(value, basestring):
+    if not isinstance(value, str):
         raise VdtTypeError(value)
     value = value.strip()
     try:
@@ -995,7 +995,7 @@ def is_list(value, min=None, max=None):
     VdtTypeError: the value "12" is of the wrong type.
     """
     (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
-    if isinstance(value, basestring):
+    if isinstance(value, str):
         raise VdtTypeError(value)
     try:
         num_members = len(value)
@@ -1064,7 +1064,7 @@ def is_string(value, min=None, max=None):
     Traceback (most recent call last):
     VdtValueTooLongError: the value "1234" is too long.
     """
-    if not isinstance(value, basestring):
+    if not isinstance(value, str):
         raise VdtTypeError(value)
     (min_len, max_len) = _is_num_param(('min', 'max'), (min, max))
     try:
@@ -1170,7 +1170,7 @@ def is_string_list(value, min=None, max=None):
     Traceback (most recent call last):
     VdtTypeError: the value "hello" is of the wrong type.
     """
-    if isinstance(value, basestring):
+    if isinstance(value, str):
         raise VdtTypeError(value)
     return [is_string(mem) for mem in is_list(value, min, max)]
 
@@ -1278,7 +1278,7 @@ def is_mixed_list(value, *args):
     >>> res_str = "'".join(res_seq)
     >>> try:
     ...     vtor.check('mixed_list("yoda")', ('a'))
-    ... except VdtParamError, err:
+    ... except VdtParamError as err:
     ...     str(err) == res_str
     1
     """
@@ -1292,7 +1292,7 @@ def is_mixed_list(value, *args):
         raise VdtValueTooLongError(value)
     try:
         return [fun_dict[arg](val) for arg, val in zip(args, value)]
-    except KeyError, e:
+    except KeyError as e:
         raise VdtParamError('mixed_list', e)
 
 
@@ -1309,7 +1309,7 @@ def is_option(value, *options):
     Traceback (most recent call last):
     VdtTypeError: the value "0" is of the wrong type.
     """
-    if not isinstance(value, basestring):
+    if not isinstance(value, str):
         raise VdtTypeError(value)
     if not value in options:
         raise VdtValueError(value)
diff --git a/python/eme/gen-eme-voucher.py b/python/eme/gen-eme-voucher.py
index 299bc71463..57089bd27b 100644
--- a/python/eme/gen-eme-voucher.py
+++ b/python/eme/gen-eme-voucher.py
@@ -10,8 +10,8 @@
 # Creates an Adobe Access signed voucher for x32/x64 windows executables
 #   Notes: This is currently python2.7 due to mozilla build system requirements
 
-from __future__ import print_function
 
+from __future__ import print_function
 import argparse, bitstring, pprint, hashlib, os, subprocess, sys, tempfile, macholib, macholib.MachO
 from pyasn1.codec.der import encoder as der_encoder
 from pyasn1.type import univ, namedtype, namedval, constraint
@@ -129,8 +129,8 @@ def parse_items(stream, items_in, items_out):
 			bits_read += bits
 			total_bits_read += bits
 		elif len(item) == 3 or len(item) == 4:
-			requirements = list(filter(lambda x: isinstance(x, dict), item[2]))
-			sub_items = list(filter(lambda x: isinstance(x, tuple), item[2]))
+			requirements = list([x for x in item[2] if isinstance(x, dict)])
+			sub_items = list([x for x in item[2] if isinstance(x, tuple)])
 
 			if not meets_requirements(items_out, requirements): continue
 
@@ -438,8 +438,8 @@ def processMachoBinary(filename):
 
 
 
-		segment_commands = list(filter(lambda x: x[0].cmd == lc_segment, header.commands))
-		text_segment_commands = list(filter(lambda x: x[1].segname.decode("utf-8").startswith("__TEXT"), segment_commands))
+		segment_commands = list([x for x in header.commands if x[0].cmd == lc_segment])
+		text_segment_commands = list([x for x in segment_commands if x[1].segname.decode("utf-8").startswith("__TEXT")])
 
 
 		code_segment_digests = SetOfCodeSegmentDigest()
@@ -518,7 +518,7 @@ def processCOFFBinary(stream):
 
 	arch_digest.setComponentByName('cpuSubType', CPUSubType('IMAGE_UNUSED'))
 
-	text_section_headers = list(filter(lambda x: (x.items['Characteristics'] & IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE, coff_header.section_headers))
+	text_section_headers = list([x for x in coff_header.section_headers if (x.items['Characteristics'] & IMAGE_SCN_MEM_EXECUTE) == IMAGE_SCN_MEM_EXECUTE])
 
 	code_segment_digests = SetOfCodeSegmentDigest()
 	code_segment_idx = 0
@@ -612,13 +612,13 @@ def main():
 			# create PEM from PFX
 			pfx_pem_path = create_temp_file(".pem")
 			temp_files += [pfx_pem_path]
-			print("Extracting PEM from PFX to:" + pfx_pem_path)
+			print(("Extracting PEM from PFX to:" + pfx_pem_path))
 			openssl_cmd(app_args, ["pkcs12", "-in", app_args.signer_pfx, "-out", pfx_pem_path], True, True)
 
 			# extract CA certs
 			pfx_cert_path = create_temp_file(".cert")
 			temp_files += [pfx_cert_path]
-			print("Extracting cert from PFX to:" + pfx_cert_path)
+			print(("Extracting cert from PFX to:" + pfx_cert_path))
 			openssl_cmd(app_args, ["pkcs12", "-in", app_args.signer_pfx, "-cacerts", "-nokeys", "-out", pfx_cert_path], True, False)
 
 			# we embed the public keychain for client validation
diff --git a/python/futures/concurrent/futures/_base.py b/python/futures/concurrent/futures/_base.py
index fbf0275120..56cd2820e6 100644
--- a/python/futures/concurrent/futures/_base.py
+++ b/python/futures/concurrent/futures/_base.py
@@ -6,6 +6,7 @@ import logging
 import threading
 import itertools
 import time
+import six
 
 __author__ = 'Brian Quinlan (brian@sweetapp.com)'
 
@@ -352,7 +353,7 @@ class Future(object):
 
     def __get_result(self):
         if self._exception:
-            raise type(self._exception), self._exception, self._traceback
+            six.reraise(type(self._exception), self._exception, self._traceback)
         else:
             return self._result
 
@@ -568,7 +569,7 @@ class Executor(object):
         if timeout is not None:
             end_time = timeout + time.time()
 
-        fs = [self.submit(fn, *args) for args in itertools.izip(*iterables)]
+        fs = [self.submit(fn, *args) for args in zip(*iterables)]
 
         # Yield must be hidden in closure so that the futures are submitted
         # before the first iterator value is required.
diff --git a/python/futures/concurrent/futures/process.py b/python/futures/concurrent/futures/process.py
index ee463f1819..ab51d9f01d 100644
--- a/python/futures/concurrent/futures/process.py
+++ b/python/futures/concurrent/futures/process.py
@@ -45,7 +45,7 @@ Process #1..n:
 
 import atexit
 from concurrent.futures import _base
-import Queue as queue
+import six.moves.queue as queue
 import multiprocessing
 import threading
 import weakref
@@ -85,20 +85,20 @@ def _python_exit():
 # (Futures in the call queue cannot be cancelled).
 EXTRA_QUEUED_CALLS = 1
 
-class _WorkItem(object):
+class _WorkItem:
     def __init__(self, future, fn, args, kwargs):
         self.future = future
         self.fn = fn
         self.args = args
         self.kwargs = kwargs
 
-class _ResultItem(object):
+class _ResultItem:
     def __init__(self, work_id, exception=None, result=None):
         self.work_id = work_id
         self.exception = exception
         self.result = result
 
-class _CallItem(object):
+class _CallItem:
     def __init__(self, work_id, fn, args, kwargs):
         self.work_id = work_id
         self.fn = fn
diff --git a/python/futures/concurrent/futures/thread.py b/python/futures/concurrent/futures/thread.py
index fa5ed0c092..38ef808e7f 100644
--- a/python/futures/concurrent/futures/thread.py
+++ b/python/futures/concurrent/futures/thread.py
@@ -5,7 +5,7 @@
 
 import atexit
 from concurrent.futures import _base
-import Queue as queue
+import six.moves.queue as queue
 import threading
 import weakref
 import sys
@@ -40,7 +40,7 @@ def _python_exit():
 
 atexit.register(_python_exit)
 
-class _WorkItem(object):
+class _WorkItem:
     def __init__(self, future, fn, args, kwargs):
         self.future = future
         self.fn = fn
diff --git a/python/futures/crawl.py b/python/futures/crawl.py
index 86e0af7fe6..7b72112b8a 100644
--- a/python/futures/crawl.py
+++ b/python/futures/crawl.py
@@ -6,7 +6,7 @@ import timeit
 import sys
 
 try:
-    from urllib2 import urlopen
+    from urllib.request import urlopen
 except ImportError:
     from urllib.request import urlopen
 
@@ -41,8 +41,8 @@ def download_urls_sequential(urls, timeout=60):
 def download_urls_with_executor(urls, executor, timeout=60):
     try:
         url_to_content = {}
-        future_to_url = dict((executor.submit(load_url, url, timeout), url)
-                             for url in urls)
+        future_to_url = {executor.submit(load_url, url, timeout): url
+                             for url in urls}
 
         for future in as_completed(future_to_url):
             try:
diff --git a/python/futures/docs/conf.py b/python/futures/docs/conf.py
index 5cea44c881..b4dbcf229d 100644
--- a/python/futures/docs/conf.py
+++ b/python/futures/docs/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # futures documentation build configuration file, created by
 # sphinx-quickstart on Wed Jun  3 19:35:34 2009.
@@ -37,8 +36,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'futures'
-copyright = u'2009-2011, Brian Quinlan'
+project = 'futures'
+copyright = '2009-2011, Brian Quinlan'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -172,8 +171,8 @@ htmlhelp_basename = 'futuresdoc'
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'futures.tex', u'futures Documentation',
-   u'Brian Quinlan', 'manual'),
+  ('index', 'futures.tex', 'futures Documentation',
+   'Brian Quinlan', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
diff --git a/python/futures/primes.py b/python/futures/primes.py
index 0da2b3e64c..a24a6b7f01 100644
--- a/python/futures/primes.py
+++ b/python/futures/primes.py
@@ -1,4 +1,3 @@
-from __future__ import with_statement
 import math
 import time
 import sys
diff --git a/python/futures/test_futures.py b/python/futures/test_futures.py
index ace340cb06..caaaa83074 100644
--- a/python/futures/test_futures.py
+++ b/python/futures/test_futures.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import os
 import subprocess
 import sys
@@ -82,7 +83,7 @@ def strip_python_stderr(stderr):
     This will typically be run on the result of the communicate() method
     of a subprocess.Popen object.
     """
-    stderr = re.sub(r"\[\d+ refs\]\r?\n?$".encode(), "".encode(), stderr).strip()
+    stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip()
     return stderr
 
 
@@ -146,7 +147,7 @@ class ExecutorMixin:
         self.executor.shutdown(wait=True)
         dt = time.time() - self.t1
         if test_support.verbose:
-            print("%.2fs" % dt)
+            print(("%.2fs" % dt))
         self.assertLess(dt, 60, "synchronization issue: test lasted too long")
 
     def _prime_executor(self):
@@ -177,16 +178,16 @@ class ExecutorShutdownTest(unittest.TestCase):
     def test_interpreter_shutdown(self):
         # Test the atexit hook for shutdown of worker threads and processes
         rc, out, err = assert_python_ok('-c', """if 1:
-            from concurrent.futures import %s
+            from concurrent.futures import {}
             from time import sleep
             from test_futures import sleep_and_print
-            t = %s(5)
+            t = {}(5)
             t.submit(sleep_and_print, 1.0, "apple")
-            """ % (self.executor_type.__name__, self.executor_type.__name__))
+            """.format(self.executor_type.__name__, self.executor_type.__name__))
         # Errors in atexit hooks don't change the process exit code, check
         # stderr manually.
         self.assertFalse(err)
-        self.assertEqual(out.strip(), "apple".encode())
+        self.assertEqual(out.strip(), b"apple")
 
     def test_hang_issue12364(self):
         fs = [self.executor.submit(time.sleep, 0.1) for _ in range(50)]
@@ -211,7 +212,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest):
     def test_context_manager_shutdown(self):
         with futures.ThreadPoolExecutor(max_workers=5) as e:
             executor = e
-            self.assertEqual(list(e.map(abs, range(-5, 5))),
+            self.assertEqual(list(e.map(abs, list(range(-5, 5)))),
                              [5, 4, 3, 2, 1, 0, 1, 2, 3, 4])
 
         for t in executor._threads:
@@ -219,7 +220,7 @@ class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest):
 
     def test_del_shutdown(self):
         executor = futures.ThreadPoolExecutor(max_workers=5)
-        executor.map(abs, range(-5, 5))
+        executor.map(abs, list(range(-5, 5)))
         threads = executor._threads
         del executor
 
@@ -245,7 +246,7 @@ class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest):
     def test_context_manager_shutdown(self):
         with futures.ProcessPoolExecutor(max_workers=5) as e:
             processes = e._processes
-            self.assertEqual(list(e.map(abs, range(-5, 5))),
+            self.assertEqual(list(e.map(abs, list(range(-5, 5)))),
                              [5, 4, 3, 2, 1, 0, 1, 2, 3, 4])
 
         for p in processes:
@@ -253,7 +254,7 @@ class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest):
 
     def test_del_shutdown(self):
         executor = futures.ProcessPoolExecutor(max_workers=5)
-        list(executor.map(abs, range(-5, 5)))
+        list(executor.map(abs, list(range(-5, 5))))
         queue_management_thread = executor._queue_management_thread
         processes = executor._processes
         del executor
@@ -273,8 +274,8 @@ class WaitTests(unittest.TestCase):
                 [CANCELLED_FUTURE, future1, future2],
                  return_when=futures.FIRST_COMPLETED)
 
-        self.assertEqual(set([future1]), done)
-        self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done)
+        self.assertEqual({future1}, done)
+        self.assertEqual({CANCELLED_FUTURE, future2}, not_done)
 
     def test_first_completed_some_already_completed(self):
         future1 = self.executor.submit(time.sleep, 1.5)
@@ -284,9 +285,9 @@ class WaitTests(unittest.TestCase):
                  return_when=futures.FIRST_COMPLETED)
 
         self.assertEqual(
-                set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]),
+                {CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE},
                 finished)
-        self.assertEqual(set([future1]), pending)
+        self.assertEqual({future1}, pending)
 
     def test_first_exception(self):
         future1 = self.executor.submit(mul, 2, 21)
@@ -297,8 +298,8 @@ class WaitTests(unittest.TestCase):
                 [future1, future2, future3],
                 return_when=futures.FIRST_EXCEPTION)
 
-        self.assertEqual(set([future1, future2]), finished)
-        self.assertEqual(set([future3]), pending)
+        self.assertEqual({future1, future2}, finished)
+        self.assertEqual({future3}, pending)
 
     def test_first_exception_some_already_complete(self):
         future1 = self.executor.submit(divmod, 21, 0)
@@ -311,10 +312,10 @@ class WaitTests(unittest.TestCase):
                  future1, future2],
                 return_when=futures.FIRST_EXCEPTION)
 
-        self.assertEqual(set([SUCCESSFUL_FUTURE,
+        self.assertEqual({SUCCESSFUL_FUTURE,
                               CANCELLED_AND_NOTIFIED_FUTURE,
-                              future1]), finished)
-        self.assertEqual(set([CANCELLED_FUTURE, future2]), pending)
+                              future1}, finished)
+        self.assertEqual({CANCELLED_FUTURE, future2}, pending)
 
     def test_first_exception_one_already_failed(self):
         future1 = self.executor.submit(time.sleep, 2)
@@ -323,8 +324,8 @@ class WaitTests(unittest.TestCase):
                  [EXCEPTION_FUTURE, future1],
                  return_when=futures.FIRST_EXCEPTION)
 
-        self.assertEqual(set([EXCEPTION_FUTURE]), finished)
-        self.assertEqual(set([future1]), pending)
+        self.assertEqual({EXCEPTION_FUTURE}, finished)
+        self.assertEqual({future1}, pending)
 
     def test_all_completed(self):
         future1 = self.executor.submit(divmod, 2, 0)
@@ -338,11 +339,11 @@ class WaitTests(unittest.TestCase):
                  future2],
                 return_when=futures.ALL_COMPLETED)
 
-        self.assertEqual(set([SUCCESSFUL_FUTURE,
+        self.assertEqual({SUCCESSFUL_FUTURE,
                               CANCELLED_AND_NOTIFIED_FUTURE,
                               EXCEPTION_FUTURE,
                               future1,
-                              future2]), finished)
+                              future2}, finished)
         self.assertEqual(set(), pending)
 
     def test_timeout(self):
@@ -357,11 +358,11 @@ class WaitTests(unittest.TestCase):
                 timeout=1.5,
                 return_when=futures.ALL_COMPLETED)
 
-        self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE,
+        self.assertEqual({CANCELLED_AND_NOTIFIED_FUTURE,
                               EXCEPTION_FUTURE,
                               SUCCESSFUL_FUTURE,
-                              future1]), finished)
-        self.assertEqual(set([future2]), pending)
+                              future1}, finished)
+        self.assertEqual({future2}, pending)
 
 
 class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests):
@@ -375,7 +376,7 @@ class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests):
         oldswitchinterval = sys.getcheckinterval()
         sys.setcheckinterval(1)
         try:
-            fs = set(self.executor.submit(future_func) for i in range(100))
+            fs = {self.executor.submit(future_func) for i in range(100)}
             event.set()
             futures.wait(fs, return_when=futures.ALL_COMPLETED)
         finally:
@@ -397,11 +398,11 @@ class AsCompletedTests(unittest.TestCase):
                  EXCEPTION_FUTURE,
                  SUCCESSFUL_FUTURE,
                  future1, future2]))
-        self.assertEqual(set(
-                [CANCELLED_AND_NOTIFIED_FUTURE,
+        self.assertEqual({
+                CANCELLED_AND_NOTIFIED_FUTURE,
                  EXCEPTION_FUTURE,
                  SUCCESSFUL_FUTURE,
-                 future1, future2]),
+                 future1, future2},
                 completed)
 
     def test_zero_timeout(self):
@@ -418,9 +419,9 @@ class AsCompletedTests(unittest.TestCase):
         except futures.TimeoutError:
             pass
 
-        self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE,
+        self.assertEqual({CANCELLED_AND_NOTIFIED_FUTURE,
                               EXCEPTION_FUTURE,
-                              SUCCESSFUL_FUTURE]),
+                              SUCCESSFUL_FUTURE},
                          completed_futures)
 
     def test_duplicate_futures(self):
@@ -452,8 +453,8 @@ class ExecutorTest(unittest.TestCase):
 
     def test_map(self):
         self.assertEqual(
-                list(self.executor.map(pow, range(10), range(10))),
-                list(map(pow, range(10), range(10))))
+                list(self.executor.map(pow, list(range(10)), list(range(10)))),
+                list(map(pow, list(range(10)), list(range(10)))))
 
     def test_map_exception(self):
         i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5])
@@ -483,7 +484,7 @@ class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest):
         def record_finished(n):
             finished.append(n)
 
-        self.executor.map(record_finished, range(10))
+        self.executor.map(record_finished, list(range(10)))
         self.executor.shutdown(wait=True)
         self.assertEqual(len(finished), 10)
 
@@ -574,18 +575,18 @@ class FutureTests(unittest.TestCase):
         self.assertTrue(was_cancelled[0])
 
     def test_repr(self):
-        self.assertRegexpMatches(repr(PENDING_FUTURE),
+        self.assertRegex(repr(PENDING_FUTURE),
                                  '<Future at 0x[0-9a-f]+ state=pending>')
-        self.assertRegexpMatches(repr(RUNNING_FUTURE),
+        self.assertRegex(repr(RUNNING_FUTURE),
                                  '<Future at 0x[0-9a-f]+ state=running>')
-        self.assertRegexpMatches(repr(CANCELLED_FUTURE),
+        self.assertRegex(repr(CANCELLED_FUTURE),
                                  '<Future at 0x[0-9a-f]+ state=cancelled>')
-        self.assertRegexpMatches(repr(CANCELLED_AND_NOTIFIED_FUTURE),
+        self.assertRegex(repr(CANCELLED_AND_NOTIFIED_FUTURE),
                                  '<Future at 0x[0-9a-f]+ state=cancelled>')
-        self.assertRegexpMatches(
+        self.assertRegex(
                 repr(EXCEPTION_FUTURE),
                 '<Future at 0x[0-9a-f]+ state=finished raised IOError>')
-        self.assertRegexpMatches(
+        self.assertRegex(
                 repr(SUCCESSFUL_FUTURE),
                 '<Future at 0x[0-9a-f]+ state=finished returned int>')
 
diff --git a/python/gdbpp/gdbpp/__init__.py b/python/gdbpp/gdbpp/__init__.py
index 1b9efbb84a..ca68dcb152 100644
--- a/python/gdbpp/gdbpp/__init__.py
+++ b/python/gdbpp/gdbpp/__init__.py
@@ -6,7 +6,7 @@
 import gdb
 import gdb.printing
 
-class GeckoPrettyPrinter(object):
+class GeckoPrettyPrinter:
     pp = gdb.printing.RegexpCollectionPrettyPrinter('GeckoPrettyPrinters')
 
     def __init__(self, name, regexp):
diff --git a/python/gdbpp/gdbpp/linkedlist.py b/python/gdbpp/gdbpp/linkedlist.py
index 60abfacb96..6f43cc15a8 100644
--- a/python/gdbpp/gdbpp/linkedlist.py
+++ b/python/gdbpp/gdbpp/linkedlist.py
@@ -15,7 +15,7 @@ from gdbpp import GeckoPrettyPrinter
 #   itself.  We do not want to start printing every item in the list whenever
 #   we run into a LinkedListElement<T>.
 @GeckoPrettyPrinter('mozilla::LinkedList', '^mozilla::LinkedList<.*>$')
-class linkedlist_printer(object):
+class linkedlist_printer:
     def __init__(self, value):
         self.value = value
         # mfbt's LinkedList has the elements of the linked list subclass from
diff --git a/python/gdbpp/gdbpp/owningthread.py b/python/gdbpp/gdbpp/owningthread.py
index 3048c8e9d3..abd7ed5792 100644
--- a/python/gdbpp/gdbpp/owningthread.py
+++ b/python/gdbpp/gdbpp/owningthread.py
@@ -7,7 +7,7 @@ import gdb
 from gdbpp import GeckoPrettyPrinter
 
 @GeckoPrettyPrinter('nsAutoOwningThread', '^nsAutoOwningThread$')
-class owning_thread_printer(object):
+class owning_thread_printer:
     def __init__(self, value):
         self.value = value
 
diff --git a/python/gdbpp/gdbpp/smartptr.py b/python/gdbpp/gdbpp/smartptr.py
index 02650f6606..a3ed6b9a2a 100644
--- a/python/gdbpp/gdbpp/smartptr.py
+++ b/python/gdbpp/gdbpp/smartptr.py
@@ -7,7 +7,7 @@ import gdb
 from gdbpp import GeckoPrettyPrinter
 
 @GeckoPrettyPrinter('nsWeakPtr', '^nsCOMPtr<nsIWeakReference>$')
-class weak_ptr_printer(object):
+class weak_ptr_printer:
     def __init__(self, value):
         self.value = value
 
@@ -19,16 +19,16 @@ class weak_ptr_printer(object):
         ref_type = proxy.dynamic_type
         weak_ptr = proxy.cast(ref_type).dereference()['mReferent']
         if not weak_ptr:
-            return '[(%s) %s]' % (weak_ptr.type, weak_ptr)
+            return '[({}) {}]'.format(weak_ptr.type, weak_ptr)
 
-        return '[(%s) %s]' % (weak_ptr.dynamic_type, weak_ptr)
+        return '[({}) {}]'.format(weak_ptr.dynamic_type, weak_ptr)
 
 @GeckoPrettyPrinter('mozilla::StaticAutoPtr', '^mozilla::StaticAutoPtr<.*>$')
 @GeckoPrettyPrinter('mozilla::StaticRefPtr', '^mozilla::StaticRefPtr<.*>$')
 @GeckoPrettyPrinter('nsAutoPtr', '^nsAutoPtr<.*>$')
 @GeckoPrettyPrinter('nsCOMPtr', '^nsCOMPtr<.*>$')
 @GeckoPrettyPrinter('RefPtr', '^RefPtr<.*>$')
-class smartptr_printer(object):
+class smartptr_printer:
     def __init__(self, value):
         self.value = value['mRawPtr']
 
@@ -38,10 +38,10 @@ class smartptr_printer(object):
         else:
             type_name = str(self.value.dereference().dynamic_type.pointer())
 
-        return '[(%s) %s]' % (type_name, str(self.value))
+        return '[({}) {}]'.format(type_name, str(self.value))
 
 @GeckoPrettyPrinter('UniquePtr', '^mozilla::UniquePtr<.*>$')
-class uniqueptr_printer(object):
+class uniqueptr_printer:
     def __init__(self, value):
         self.value = value['mTuple']['mFirstA']
 
@@ -51,4 +51,4 @@ class uniqueptr_printer(object):
         else:
             type_name = str(self.value.dereference().dynamic_type.pointer())
 
-        return '[(%s) %s]' % (type_name, str(self.value))
+        return '[({}) {}]'.format(type_name, str(self.value))
diff --git a/python/gdbpp/gdbpp/string.py b/python/gdbpp/gdbpp/string.py
index 6bf7fcebbd..7f70ef5138 100644
--- a/python/gdbpp/gdbpp/string.py
+++ b/python/gdbpp/gdbpp/string.py
@@ -7,7 +7,7 @@ import gdb
 from gdbpp import GeckoPrettyPrinter
 
 @GeckoPrettyPrinter('nsString', '^ns.*String$')
-class string_printer(object):
+class string_printer:
     def __init__(self, value):
         self.value = value
 
diff --git a/python/gdbpp/gdbpp/tarray.py b/python/gdbpp/gdbpp/tarray.py
index dae6b1b496..aa38034d69 100644
--- a/python/gdbpp/gdbpp/tarray.py
+++ b/python/gdbpp/gdbpp/tarray.py
@@ -11,7 +11,7 @@ from gdbpp import GeckoPrettyPrinter
 @GeckoPrettyPrinter('FallibleTArray', '^FallibleTArray<.*>$')
 @GeckoPrettyPrinter('AutoTArray', '^AutoTArray<.*>$')
 @GeckoPrettyPrinter('nsTArray', '^nsTArray<.*>$')
-class tarray_printer(object):
+class tarray_printer:
     def __init__(self, value):
         self.value = value
         self.elem_type = value.type.template_argument(0)
diff --git a/python/gdbpp/gdbpp/thashtable.py b/python/gdbpp/gdbpp/thashtable.py
index fb11f95cb3..680377f46d 100644
--- a/python/gdbpp/gdbpp/thashtable.py
+++ b/python/gdbpp/gdbpp/thashtable.py
@@ -47,7 +47,7 @@ def walk_template_to_given_base(value, desired_tag_prefix):
 @GeckoPrettyPrinter('nsRefPtrHashtable', '^nsRefPtrHashtable<.*>$')
 @GeckoPrettyPrinter('nsBaseHashtable', '^nsBaseHashtable<.*>$')
 @GeckoPrettyPrinter('nsTHashtable', '^nsTHashtable<.*>$')
-class thashtable_printer(object):
+class thashtable_printer:
     def __init__(self, outer_value):
         self.outermost_type = outer_value.type
 
diff --git a/python/jsmin/jsmin/__init__.py b/python/jsmin/jsmin/__init__.py
index 033a087019..32b17d0cb8 100644
--- a/python/jsmin/jsmin/__init__.py
+++ b/python/jsmin/jsmin/__init__.py
@@ -45,7 +45,7 @@ def jsmin(js, **kwargs):
     returns a minified version of the javascript string
     """
     if not is_3:        
-        if cStringIO and not isinstance(js, unicode):
+        if cStringIO and not isinstance(js, str):
             # strings can use cStringIO for a 3x performance
             # improvement, but unicode (in python2) cannot
             klass = cStringIO.StringIO
@@ -59,7 +59,7 @@ def jsmin(js, **kwargs):
     return outs.getvalue()
 
 
-class JavascriptMinify(object):
+class JavascriptMinify:
     """
     Minify an input stream of javascript, writing
     to an output stream
diff --git a/python/jsmin/jsmin/test.py b/python/jsmin/jsmin/test.py
index 6f7f627fde..705fcbbe46 100644
--- a/python/jsmin/jsmin/test.py
+++ b/python/jsmin/jsmin/test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import unittest
 import jsmin
 import sys
@@ -8,13 +9,13 @@ class JsTests(unittest.TestCase):
 
     def assertEqual(self, thing1, thing2):
         if thing1 != thing2:
-            print(repr(thing1), repr(thing2))
+            print((repr(thing1), repr(thing2)))
             raise AssertionError
         return True
     
     def assertMinified(self, js_input, expected, **kwargs):
         minified = jsmin.jsmin(js_input, **kwargs)
-        assert minified == expected, "%r != %r" % (minified, expected)
+        assert minified == expected, "{!r} != {!r}".format(minified, expected)
         
     def testQuoted(self):
         js = r'''
@@ -260,8 +261,8 @@ var  foo    =  "hey";
         assert output == "function foo(''){}"
     
     def testUnicode(self):
-        instr = u'\u4000 //foo'
-        expected = u'\u4000'
+        instr = '\u4000 //foo'
+        expected = '\u4000'
         output = jsmin.jsmin(instr)
         self.assertEqual(output, expected)
 
@@ -285,8 +286,8 @@ var  foo    =  "hey";
         self.assertMinified("return//comment...\r\na", "return\na")
     
     def testSingleComment2(self):
-        self.assertMinified('x.replace(/\//, "_")// slash to underscore',
-                'x.replace(/\//,"_")')
+        self.assertMinified(r'x.replace(/\//, "_")// slash to underscore',
+                r'x.replace(/\//,"_")')
 
     def testSlashesNearComments(self):
         original = '''
diff --git a/python/jsmin/setup.py b/python/jsmin/setup.py
index 8fff566023..dc96edae32 100644
--- a/python/jsmin/setup.py
+++ b/python/jsmin/setup.py
@@ -6,8 +6,7 @@ os.environ['COPYFILE_DISABLE'] = 'true'  # this disables including resource fork
 
 
 extra = {}
-if sys.version_info >= (3,0):
-    extra['use_2to3'] = True
+extra['use_2to3'] = True
 
 setup(
     name="jsmin",
diff --git a/python/lldbutils/lldbutils/general.py b/python/lldbutils/lldbutils/general.py
index 27cf19aabb..452dd58652 100644
--- a/python/lldbutils/lldbutils/general.py
+++ b/python/lldbutils/lldbutils/general.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import lldb
 from lldbutils import utils
 
@@ -43,28 +44,28 @@ def prefcnt(debugger, command, result, dict):
     frame = thread.GetSelectedFrame()
     obj = frame.EvaluateExpression(command)
     if obj.GetError().Fail():
-        print "could not evaluate expression"
+        print("could not evaluate expression")
         return
     obj = utils.dereference(obj)
     field = obj.GetChildMemberWithName("mRefCnt")
     if field.GetError().Fail():
         field = obj.GetChildMemberWithName("refCnt")
     if field.GetError().Fail():
-        print "not a refcounted object"
+        print("not a refcounted object")
         return
     refcnt_type = field.GetType().GetCanonicalType().GetName()
     if refcnt_type == "nsAutoRefCnt":
-        print field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)
+        print((field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)))
     elif refcnt_type == "nsCycleCollectingAutoRefCnt":
-        print field.GetChildMemberWithName("mRefCntAndFlags").GetValueAsUnsigned(0) >> 2
+        print((field.GetChildMemberWithName("mRefCntAndFlags").GetValueAsUnsigned(0) >> 2))
     elif refcnt_type == "mozilla::ThreadSafeAutoRefCnt":
-        print field.GetChildMemberWithName("mValue").GetChildMemberWithName("mValue").GetValueAsUnsigned(0)
+        print((field.GetChildMemberWithName("mValue").GetChildMemberWithName("mValue").GetValueAsUnsigned(0)))
     elif refcnt_type == "int":  # non-atomic mozilla::RefCounted object
-        print field.GetValueAsUnsigned(0)
+        print((field.GetValueAsUnsigned(0)))
     elif refcnt_type == "mozilla::Atomic<int>":  # atomic mozilla::RefCounted object
-        print field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)
+        print((field.GetChildMemberWithName("mValue").GetValueAsUnsigned(0)))
     else:
-        print "unknown mRefCnt type " + refcnt_type
+        print(("unknown mRefCnt type " + refcnt_type))
 
 # Used to work around http://llvm.org/bugs/show_bug.cgi?id=22211
 def callfunc(debugger, command, result, dict):
@@ -72,7 +73,7 @@ def callfunc(debugger, command, result, dict):
        The function is assumed to return void."""
 
     if '(' not in command:
-        print 'Usage: callfunc your_function(args)'
+        print('Usage: callfunc your_function(args)')
         return
 
     command_parts = command.split('(')
@@ -82,7 +83,7 @@ def callfunc(debugger, command, result, dict):
     target = debugger.GetSelectedTarget()
     symbols = target.FindFunctions(funcname).symbols
     if not symbols:
-        print 'Could not find a function symbol for a function called "%s"' % funcname
+        print(('Could not find a function symbol for a function called "%s"' % funcname))
         return
 
     sym = symbols[0]
diff --git a/python/lldbutils/lldbutils/gfx.py b/python/lldbutils/lldbutils/gfx.py
index 1ad9a37a7f..d020849174 100644
--- a/python/lldbutils/lldbutils/gfx.py
+++ b/python/lldbutils/lldbutils/gfx.py
@@ -25,7 +25,7 @@ def summarize_nscolor(valobj, internal_dict):
         return "transparent"
     if value & 0xff000000 != 0xff000000:
         return "rgba(%d, %d, %d, %f)" % (value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, ((value >> 24) & 0xff) / 255.0)
-    color = "#%02x%02x%02x" % (value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff)
+    color = "#{:02x}{:02x}{:02x}".format(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff)
     if color in colors:
         return colors[color]
     return color
@@ -100,7 +100,7 @@ def summarize_rect(valobj, internal_dict):
     y = valobj.GetChildMemberWithName("y").GetValue()
     width = valobj.GetChildMemberWithName("width").GetValue()
     height = valobj.GetChildMemberWithName("height").GetValue()
-    return "%s, %s, %s, %s" % (x, y, width, height)
+    return "{}, {}, {}, {}".format(x, y, width, height)
 
 def rect_is_empty(valobj):
     width = valobj.GetChildMemberWithName("width").GetValueAsSigned()
diff --git a/python/mach/mach/base.py b/python/mach/mach/base.py
index 3556dc6e57..e039c82a0f 100644
--- a/python/mach/mach/base.py
+++ b/python/mach/mach/base.py
@@ -2,10 +2,9 @@
 # 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, unicode_literals
 
 
-class CommandContext(object):
+class CommandContext:
     """Holds run-time state so it can easily be passed to command providers."""
     def __init__(self, cwd=None, settings=None, log_manager=None,
         commands=None, **kwargs):
diff --git a/python/mach/mach/commands/commandinfo.py b/python/mach/mach/commands/commandinfo.py
index cce85f859d..c90e4d6491 100644
--- a/python/mach/mach/commands/commandinfo.py
+++ b/python/mach/mach/commands/commandinfo.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 from mach.decorators import (
     CommandProvider,
     Command,
@@ -12,7 +12,7 @@ from mach.decorators import (
 
 
 @CommandProvider
-class BuiltinCommands(object):
+class BuiltinCommands:
     def __init__(self, context):
         self.context = context
 
@@ -25,7 +25,7 @@ class BuiltinCommands(object):
     @Command('mach-commands', category='misc',
         description='List all mach commands.')
     def commands(self):
-        print("\n".join(self.command_keys))
+        print(("\n".join(self.command_keys)))
 
     @Command('mach-debug-commands', category='misc',
         description='Show info about available mach commands.')
@@ -44,10 +44,10 @@ class BuiltinCommands(object):
             method = getattr(cls, getattr(handler, 'method'))
 
             print(command)
-            print('=' * len(command))
+            print(('=' * len(command)))
             print('')
-            print('File: %s' % inspect.getsourcefile(method))
-            print('Class: %s' % cls.__name__)
-            print('Method: %s' % handler.method)
+            print(('File: %s' % inspect.getsourcefile(method)))
+            print(('Class: %s' % cls.__name__))
+            print(('Method: %s' % handler.method))
             print('')
 
diff --git a/python/mach/mach/commands/settings.py b/python/mach/mach/commands/settings.py
index d5bb807d82..4493637974 100644
--- a/python/mach/mach/commands/settings.py
+++ b/python/mach/mach/commands/settings.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 import os
 from textwrap import TextWrapper
 
@@ -23,7 +23,7 @@ Please run:
 
 
 @CommandProvider
-class Settings(object):
+class Settings:
     """Interact with settings for mach.
 
     Currently, we only provide functionality to view what settings are
@@ -43,19 +43,19 @@ class Settings(object):
             for section in sorted(self._settings):
                 for option in sorted(self._settings[section]._settings):
                     short, full = self._settings.option_help(section, option)
-                    print('%s.%s -- %s' % (section, option, short))
+                    print(('{}.{} -- {}'.format(section, option, short)))
             return
 
         wrapper = TextWrapper(initial_indent='# ', subsequent_indent='# ')
         for section in sorted(self._settings):
-            print('[%s]' % section)
+            print(('[%s]' % section))
 
             for option in sorted(self._settings[section]._settings):
                 short, full = self._settings.option_help(section, option)
-                print(wrapper.fill(full))
+                print((wrapper.fill(full)))
 
                 if option != '*':
-                    print(';%s =' % option)
+                    print((';%s =' % option))
                     print('')
 
     @SubCommand('settings', 'locale-gen',
@@ -82,9 +82,9 @@ class Settings(object):
             self._gen_section(section, **kwargs)
 
         if not self.was_prompted:
-            print("All specified options already have an {} translation. "
+            print(("All specified options already have an {} translation. "
                   "To overwrite existing translations, pass --overwrite."
-                  .format(kwargs['locale']))
+                  .format(kwargs['locale'])))
 
     def _gen_section(self, section, **kwargs):
         if '.' in section:
@@ -122,7 +122,7 @@ class Settings(object):
 
             self.was_prompted = True
 
-            msgstr = raw_input("Translate {} to {}:\n"
+            msgstr = input("Translate {} to {}:\n"
                                .format(msgid, locale))
             entry.msgstr = msgstr
 
diff --git a/python/mach/mach/config.py b/python/mach/mach/config.py
index 26c9a4482c..86999aecd3 100644
--- a/python/mach/mach/config.py
+++ b/python/mach/mach/config.py
@@ -24,20 +24,16 @@ gettext .po and .mo file for the en_US locale. The |mach settings locale-gen|
 command can be used to populate these files.
 """
 
-from __future__ import absolute_import, unicode_literals
 
 import collections
+import collections.abc
 import gettext
 import os
 import sys
 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 configparser import RawConfigParser, NoSectionError
+str_type = str
 
 
 TRANSLATION_NOT_FOUND = """
@@ -52,7 +48,7 @@ class ConfigException(Exception):
     pass
 
 
-class ConfigType(object):
+class ConfigType:
     """Abstract base class for config values."""
 
     @staticmethod
@@ -149,7 +145,7 @@ TYPE_CLASSES = {
 }
 
 
-class DefaultValue(object):
+class DefaultValue:
     pass
 
 
@@ -163,11 +159,11 @@ def reraise_attribute_error(func):
             return func(*args, **kwargs)
         except KeyError:
             exc_class, exc, tb = sys.exc_info()
-            raise AttributeError().__class__, exc, tb
+            raise AttributeError(str(exc)).with_traceback(tb)
     return _
 
 
-class ConfigSettings(collections.Mapping):
+class ConfigSettings(collections.abc.Mapping):
     """Interface for configuration settings.
 
     This is the main interface to the configuration.
@@ -213,7 +209,7 @@ class ConfigSettings(collections.Mapping):
     will result in exceptions being raised.
     """
 
-    class ConfigSection(collections.MutableMapping, object):
+    class ConfigSection(collections.abc.MutableMapping):
         """Represents an individual config section."""
         def __init__(self, config, name, settings):
             object.__setattr__(self, '_config', config)
@@ -242,7 +238,7 @@ class ConfigSettings(collections.Mapping):
             meta['type_cls'].validate(value)
 
             if 'choices' in meta and value not in meta['choices']:
-                raise ValueError("Value '%s' must be one of: %s" % (
+                raise ValueError("Value '{}' must be one of: {}".format(
                                  value, ', '.join(sorted(meta['choices']))))
 
         # MutableMapping interface
@@ -318,7 +314,7 @@ class ConfigSettings(collections.Mapping):
         """
         filtered = [f for f in filenames if os.path.exists(f)]
 
-        fps = [open(f, 'rt') for f in filtered]
+        fps = [open(f) for f in filtered]
         self.load_fps(fps)
         self.loaded_files.update(set(filtered))
         for fp in fps:
@@ -328,7 +324,7 @@ class ConfigSettings(collections.Mapping):
         """Load config data by reading file objects."""
 
         for fp in fps:
-            self._config.readfp(fp)
+            self._config.read_file(fp)
 
     def write(self, fh):
         """Write the config to a file object."""
@@ -357,7 +353,7 @@ class ConfigSettings(collections.Mapping):
             extra -- A dict of additional key/value pairs to add to the
                 setting metadata.
         """
-        if isinstance(type_cls, basestring):
+        if isinstance(type_cls, str):
             type_cls = TYPE_CLASSES[type_cls]
 
         meta = {
@@ -391,7 +387,7 @@ class ConfigSettings(collections.Mapping):
             section, option = setting[0].split('.')
 
             if option in config_settings[section]:
-                raise ConfigException('Setting has already been registered: %s.%s' % (
+                raise ConfigException('Setting has already been registered: {}.{}'.format(
                                 section, option))
 
             meta = self._format_metadata(provider, section, option, *setting[1:])
@@ -423,8 +419,8 @@ class ConfigSettings(collections.Mapping):
                                 fallback=True)
         t.add_fallback(default)
 
-        short = t.ugettext('%s.%s.short' % (section, option))
-        full = t.ugettext('%s.%s.full' % (section, option))
+        short = t.gettext('{}.{}.short'.format(section, option))
+        full = t.gettext('{}.{}.full'.format(section, option))
 
         return (short, full)
 
diff --git a/python/mach/mach/decorators.py b/python/mach/mach/decorators.py
index 6c1713d7f0..5e3ba0e952 100644
--- a/python/mach/mach/decorators.py
+++ b/python/mach/mach/decorators.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import argparse
 import collections
@@ -14,7 +13,7 @@ from .base import MachError
 from .registrar import Registrar
 
 
-class _MachCommand(object):
+class _MachCommand:
     """Container for mach command metadata.
 
     Mach commands contain lots of attributes. This class exists to capture them
@@ -110,8 +109,8 @@ def CommandProvider(cls):
     # Tell mach driver whether to pass context argument to __init__.
     pass_context = False
 
-    if inspect.ismethod(cls.__init__):
-        spec = inspect.getargspec(cls.__init__)
+    if inspect.isfunction(cls.__init__) or inspect.ismethod(cls.__init__):
+        spec = inspect.getfullargspec(cls.__init__)
 
         if len(spec.args) > 2:
             msg = 'Mach @CommandProvider class %s implemented incorrectly. ' + \
@@ -151,7 +150,7 @@ def CommandProvider(cls):
               'Conditions argument must take a list ' + \
               'of functions. Found %s instead.'
 
-        if not isinstance(command.conditions, collections.Iterable):
+        if not isinstance(command.conditions, collections.abc.Iterable):
             msg = msg % (command.name, type(command.conditions))
             raise MachError(msg)
 
@@ -206,7 +205,7 @@ def CommandProvider(cls):
     return cls
 
 
-class Command(object):
+class Command:
     """Decorator for functions or methods that provide a mach command.
 
     The decorator accepts arguments that define basic attributes of the
@@ -238,7 +237,7 @@ class Command(object):
 
         return func
 
-class SubCommand(object):
+class SubCommand:
     """Decorator for functions or methods that provide a sub-command.
 
     Mach commands can have sub-commands. e.g. ``mach command foo`` or
@@ -267,7 +266,7 @@ class SubCommand(object):
 
         return func
 
-class CommandArgument(object):
+class CommandArgument:
     """Decorator for additional arguments to mach subcommands.
 
     This decorator should be used to add arguments to mach commands. Arguments
@@ -298,7 +297,7 @@ class CommandArgument(object):
         return func
 
 
-class CommandArgumentGroup(object):
+class CommandArgumentGroup:
     """Decorator for additional argument groups to mach commands.
 
     This decorator should be used to add arguments groups to mach commands.
diff --git a/python/mach/mach/dispatcher.py b/python/mach/mach/dispatcher.py
index 5604d981d7..02b532989b 100644
--- a/python/mach/mach/dispatcher.py
+++ b/python/mach/mach/dispatcher.py
@@ -2,8 +2,8 @@
 # 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, unicode_literals
 
+from __future__ import print_function
 import argparse
 import difflib
 import shlex
@@ -375,7 +375,7 @@ class CommandAction(argparse.Action):
             ' subcommand [subcommand arguments]'
         group = parser.add_argument_group('Sub Commands')
 
-        for subcommand, subhandler in sorted(handler.subcommand_handlers.iteritems()):
+        for subcommand, subhandler in sorted(handler.subcommand_handlers.items()):
             group.add_argument(subcommand, help=subhandler.description,
                 action='store_true')
 
@@ -437,13 +437,13 @@ def format_docstring(docstring):
     if not docstring:
         return ''
     lines = docstring.expandtabs().splitlines()
-    indent = sys.maxint
+    indent = sys.maxsize
     for line in lines[1:]:
         stripped = line.lstrip()
         if stripped:
             indent = min(indent, len(line) - len(stripped))
     trimmed = [lines[0].strip()]
-    if indent < sys.maxint:
+    if indent < sys.maxsize:
         for line in lines[1:]:
             trimmed.append(line[indent:].rstrip())
     while trimmed and not trimmed[-1]:
diff --git a/python/mach/mach/logging.py b/python/mach/mach/logging.py
index 729e6cb3d9..94253aa2e4 100644
--- a/python/mach/mach/logging.py
+++ b/python/mach/mach/logging.py
@@ -6,7 +6,6 @@
 # support for a structured logging framework built on top of Python's built-in
 # logging framework.
 
-from __future__ import absolute_import, unicode_literals
 
 try:
     import blessings
@@ -75,7 +74,7 @@ class StructuredHumanFormatter(logging.Formatter):
 
         elapsed = self._time(record)
 
-        return '%s %s' % (format_seconds(elapsed), f)
+        return '{} {}'.format(format_seconds(elapsed), f)
 
     def _time(self, record):
         t = record.created - self.start_time
@@ -102,7 +101,7 @@ class StructuredTerminalFormatter(StructuredHumanFormatter):
 
         t = self.terminal.blue(format_seconds(self._time(record)))
 
-        return '%s %s' % (t, self._colorize(f))
+        return '{} {}'.format(t, self._colorize(f))
 
     def _colorize(self, s):
         if not self.terminal:
@@ -129,7 +128,7 @@ class StructuredTerminalFormatter(StructuredHumanFormatter):
         return result
 
 
-class LoggingManager(object):
+class LoggingManager:
     """Holds and controls global logging state.
 
     An application should instantiate one of these and configure it as needed.
diff --git a/python/mach/mach/main.py b/python/mach/mach/main.py
index dec3d7dfd7..e0cf93f961 100644
--- a/python/mach/mach/main.py
+++ b/python/mach/mach/main.py
@@ -5,16 +5,16 @@
 # This module provides functionality for the command-line build tool
 # (mach). It is packaged as a module because everything is a library.
 
-from __future__ import absolute_import, print_function, unicode_literals
-from collections import Iterable
+from collections.abc import Iterable
 
 import argparse
 import codecs
-import imp
+import importlib.util
 import logging
 import os
 import sys
 import traceback
+import types
 import uuid
 
 from .base import (
@@ -139,7 +139,7 @@ class ArgumentParser(argparse.ArgumentParser):
         return text
 
 
-class ContextWrapper(object):
+class ContextWrapper:
     def __init__(self, context, handler):
         object.__setattr__(self, '_context', context)
         object.__setattr__(self, '_handler', handler)
@@ -162,7 +162,7 @@ class ContextWrapper(object):
 
 
 @CommandProvider
-class Mach(object):
+class Mach:
     """Main mach driver type.
 
     This type is responsible for holding global mach state and dispatching
@@ -256,13 +256,16 @@ To see more help for a specific command, run:
         if module_name is None:
             # Ensure parent module is present otherwise we'll (likely) get
             # an error due to unknown parent.
-            if b'mach.commands' not in sys.modules:
-                mod = imp.new_module(b'mach.commands')
-                sys.modules[b'mach.commands'] = mod
+            if 'mach.commands' not in sys.modules:
+                mod = types.ModuleType('mach.commands')
+                sys.modules['mach.commands'] = mod
 
-            module_name = 'mach.commands.%s' % uuid.uuid1().get_hex()
+            module_name = 'mach.commands.%s' % uuid.uuid1().hex
 
-        imp.load_source(module_name, path)
+        spec = importlib.util.spec_from_file_location(module_name, path)
+        mod = importlib.util.module_from_spec(spec)
+        sys.modules[module_name] = mod
+        spec.loader.exec_module(mod)
 
     def load_commands_from_entry_point(self, group='mach.providers'):
         """Scan installed packages for mach command provider entry points. An
@@ -347,7 +350,7 @@ To see more help for a specific command, run:
             # is a TTY. This provides a mechanism to allow said processes to
             # enable emitting code codes, for example.
             if os.isatty(orig_stdout.fileno()):
-                os.environ[b'MACH_STDOUT_ISATTY'] = b'1'
+                os.environ['MACH_STDOUT_ISATTY'] = '1'
 
             return self._run(argv)
         except KeyboardInterrupt:
@@ -528,7 +531,7 @@ To see more help for a specific command, run:
 
             machrc, .machrc
         """
-        if isinstance(paths, basestring):
+        if isinstance(paths, str):
             paths = [paths]
 
         valid_names = ('machrc', '.machrc')
@@ -541,8 +544,7 @@ To see more help for a specific command, run:
                 if os.path.isfile(path):
                     return path
 
-        files = map(find_in_dir, self.settings_paths)
-        files = filter(bool, files)
+        files = list(filter(bool, map(find_in_dir, self.settings_paths)))
 
         self.settings.load_files(files)
 
@@ -560,7 +562,7 @@ To see more help for a specific command, run:
             action='store_true', default=False,
             help='Print verbose output.')
         global_group.add_argument('-l', '--log-file', dest='logfile',
-            metavar='FILENAME', type=argparse.FileType('ab'),
+            metavar='FILENAME', type=argparse.FileType('a'),
             help='Filename to write log data to.')
         global_group.add_argument('--log-interval', dest='log_interval',
             action='store_true', default=False,
diff --git a/python/mach/mach/mixin/logging.py b/python/mach/mach/mixin/logging.py
index 5c37b54f1b..6b31d58753 100644
--- a/python/mach/mach/mixin/logging.py
+++ b/python/mach/mach/mixin/logging.py
@@ -2,12 +2,11 @@
 # 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, unicode_literals
 
 import logging
 
 
-class LoggingMixin(object):
+class LoggingMixin:
     """Provides functionality to control logging."""
 
     def populate_logger(self, name=None):
diff --git a/python/mach/mach/mixin/process.py b/python/mach/mach/mixin/process.py
index b8f0eac029..7db0e1d4e2 100644
--- a/python/mach/mach/mixin/process.py
+++ b/python/mach/mach/mixin/process.py
@@ -4,7 +4,6 @@
 
 # This module provides mixins to perform process execution.
 
-from __future__ import absolute_import, unicode_literals
 
 import logging
 import os
@@ -101,24 +100,20 @@ class ProcessExecutionMixin(LoggingMixin):
             if append_env:
                 use_env.update(append_env)
 
-        self.log(logging.DEBUG, 'process', {'env': use_env}, 'Environment: {env}')
-
-        # There is a bug in subprocess where it doesn't like unicode types in
-        # environment variables. Here, ensure all unicode are converted to
-        # binary. utf-8 is our globally assumed default. If the caller doesn't
-        # want UTF-8, they shouldn't pass in a unicode instance.
+        # Ensure all environment keys and values are str (not bytes) for
+        # Python 3 compatibility with subprocess and JSON logging.
         normalized_env = {}
         for k, v in use_env.items():
-            if isinstance(k, unicode):
-                k = k.encode('utf-8', 'strict')
-
-            if isinstance(v, unicode):
-                v = v.encode('utf-8', 'strict')
-
+            if isinstance(k, bytes):
+                k = k.decode('utf-8', 'replace')
+            if isinstance(v, bytes):
+                v = v.decode('utf-8', 'replace')
             normalized_env[k] = v
 
         use_env = normalized_env
 
+        self.log(logging.DEBUG, 'process', {'env': use_env}, 'Environment: {env}')
+
         if pass_thru:
             proc = subprocess.Popen(args, cwd=cwd, env=use_env)
             status = None
diff --git a/python/mach/mach/registrar.py b/python/mach/mach/registrar.py
index 63c9099c08..098cd7e51e 100644
--- a/python/mach/mach/registrar.py
+++ b/python/mach/mach/registrar.py
@@ -2,8 +2,8 @@
 # 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, unicode_literals
 
+from __future__ import print_function
 from .base import MachError
 
 INVALID_COMMAND_CONTEXT = r'''
@@ -14,7 +14,7 @@ Run |mach help| to show a list of all commands available to the current context.
 '''.lstrip()
 
 
-class MachRegistrar(object):
+class MachRegistrar:
     """Container for mach command and config providers."""
 
     def __init__(self):
@@ -78,7 +78,7 @@ class MachRegistrar(object):
                     fail_conditions.append(c)
 
             if fail_conditions:
-                print(self._condition_failed_message(handler.name, fail_conditions))
+                print((self._condition_failed_message(handler.name, fail_conditions)))
                 return 1
 
         fn = getattr(instance, handler.method)
@@ -90,7 +90,7 @@ class MachRegistrar(object):
             result = fn(**kwargs)
 
         result = result or 0
-        assert isinstance(result, (int, long))
+        assert isinstance(result, int)
 
         if context:
             postrun = getattr(context, 'post_dispatch_handler', None)
diff --git a/python/mach/mach/terminal.py b/python/mach/mach/terminal.py
index 9115211e02..0f787ff9a6 100644
--- a/python/mach/mach/terminal.py
+++ b/python/mach/mach/terminal.py
@@ -8,7 +8,6 @@ All the terminal interaction code is consolidated so the complexity can be in
 one place, away from code that is commonly looked at.
 """
 
-from __future__ import absolute_import, print_function, unicode_literals
 
 import logging
 import sys
@@ -52,14 +51,14 @@ class LoggingHandler(logging.Handler):
         self.flush()
 
 
-class TerminalFooter(object):
+class TerminalFooter:
     """Represents something drawn on the bottom of a terminal."""
     def __init__(self, terminal):
         self.t = terminal
         self.fh = sys.stdout
 
     def _clear_lines(self, n):
-        for i in xrange(n):
+        for i in range(n):
             self.fh.write(self.t.move_x(0))
             self.fh.write(self.t.clear_eol())
             self.fh.write(self.t.move_up())
diff --git a/python/mach/mach/test/common.py b/python/mach/mach/test/common.py
index f68ff50950..4ff985c678 100644
--- a/python/mach/mach/test/common.py
+++ b/python/mach/mach/test/common.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from StringIO import StringIO
 import os
diff --git a/python/mach/mach/test/providers/basic.py b/python/mach/mach/test/providers/basic.py
index f2e64e6d65..ea36efc525 100644
--- a/python/mach/mach/test/providers/basic.py
+++ b/python/mach/mach/test/providers/basic.py
@@ -1,7 +1,6 @@
 # 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 unicode_literals
 
 from mach.decorators import (
     CommandArgument,
@@ -11,7 +10,7 @@ from mach.decorators import (
 
 
 @CommandProvider
-class ConditionsProvider(object):
+class ConditionsProvider:
     @Command('cmd_foo', category='testing')
     def run_foo(self):
         pass
diff --git a/python/mach/mach/test/providers/conditions.py b/python/mach/mach/test/providers/conditions.py
index a95429752d..35b2c8cd4a 100644
--- a/python/mach/mach/test/providers/conditions.py
+++ b/python/mach/mach/test/providers/conditions.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from mach.decorators import (
     CommandProvider,
@@ -18,7 +17,7 @@ def is_bar(cls):
     return cls.bar
 
 @CommandProvider
-class ConditionsProvider(object):
+class ConditionsProvider:
     foo = True
     bar = False
 
@@ -35,7 +34,7 @@ class ConditionsProvider(object):
         pass
 
 @CommandProvider
-class ConditionsContextProvider(object):
+class ConditionsContextProvider:
     def __init__(self, context):
         self.foo = context.foo
         self.bar = context.bar
diff --git a/python/mach/mach/test/providers/conditions_invalid.py b/python/mach/mach/test/providers/conditions_invalid.py
index 22284d4dca..597c7d24a7 100644
--- a/python/mach/mach/test/providers/conditions_invalid.py
+++ b/python/mach/mach/test/providers/conditions_invalid.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from mach.decorators import (
     CommandProvider,
@@ -10,7 +9,7 @@ from mach.decorators import (
 )
 
 @CommandProvider
-class ConditionsProvider(object):
+class ConditionsProvider:
     @Command('cmd_foo', category='testing', conditions=["invalid"])
     def run_foo(self):
         pass
diff --git a/python/mach/mach/test/providers/throw.py b/python/mach/mach/test/providers/throw.py
index 06bee01eec..f7ae42ca17 100644
--- a/python/mach/mach/test/providers/throw.py
+++ b/python/mach/mach/test/providers/throw.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import time
 
@@ -16,7 +15,7 @@ from mach.test.providers import throw2
 
 
 @CommandProvider
-class TestCommandProvider(object):
+class TestCommandProvider:
     @Command('throw', category='testing')
     @CommandArgument('--message', '-m', default='General Error')
     def throw(self, message):
diff --git a/python/mach/mach/test/test_conditions.py b/python/mach/mach/test/test_conditions.py
index 20080687e3..d637ca8404 100644
--- a/python/mach/mach/test/test_conditions.py
+++ b/python/mach/mach/test/test_conditions.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 
@@ -34,8 +33,8 @@ class TestConditions(TestBase):
     def test_conditions_pass(self):
         """Test that a command which passes its conditions is runnable."""
 
-        self.assertEquals((0, '', ''), self._run_mach(['cmd_foo']))
-        self.assertEquals((0, '', ''), self._run_mach(['cmd_foo_ctx'], _populate_context))
+        self.assertEqual((0, '', ''), self._run_mach(['cmd_foo']))
+        self.assertEqual((0, '', ''), self._run_mach(['cmd_foo_ctx'], _populate_context))
 
     def test_invalid_context_message(self):
         """Test that commands which do not pass all their conditions
@@ -47,17 +46,17 @@ class TestConditions(TestBase):
 
         for name in ('cmd_bar', 'cmd_foobar'):
             result, stdout, stderr = self._run_mach([name])
-            self.assertEquals(1, result)
+            self.assertEqual(1, result)
 
             fail_msg = Registrar._condition_failed_message(name, fail_conditions)
-            self.assertEquals(fail_msg.rstrip(), stdout.rstrip())
+            self.assertEqual(fail_msg.rstrip(), stdout.rstrip())
 
         for name in ('cmd_bar_ctx', 'cmd_foobar_ctx'):
             result, stdout, stderr = self._run_mach([name], _populate_context)
-            self.assertEquals(1, result)
+            self.assertEqual(1, result)
 
             fail_msg = Registrar._condition_failed_message(name, fail_conditions)
-            self.assertEquals(fail_msg.rstrip(), stdout.rstrip())
+            self.assertEqual(fail_msg.rstrip(), stdout.rstrip())
 
     def test_invalid_type(self):
         """Test that a condition which is not callable raises an exception."""
diff --git a/python/mach/mach/test/test_config.py b/python/mach/mach/test/test_config.py
index d48dff67b2..a546c27eb2 100644
--- a/python/mach/mach/test/test_config.py
+++ b/python/mach/mach/test/test_config.py
@@ -1,7 +1,6 @@
 # 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 unicode_literals
 
 import sys
 import unittest
@@ -22,10 +21,7 @@ from mach.decorators import SettingsProvider
 from mozunit import main
 
 
-if sys.version_info[0] == 3:
-    str_type = str
-else:
-    str_type = basestring
+str_type = str
 
 CONFIG1 = r"""
 [foo]
@@ -41,7 +37,7 @@ bar = value2
 """
 
 @SettingsProvider
-class Provider1(object):
+class Provider1:
     config_settings = [
         ('foo.bar', StringType),
         ('foo.baz', PathType),
@@ -49,7 +45,7 @@ class Provider1(object):
 
 
 @SettingsProvider
-class ProviderDuplicate(object):
+class ProviderDuplicate:
     config_settings = [
         ('dupesect.foo', StringType),
         ('dupesect.foo', StringType),
@@ -57,7 +53,7 @@ class ProviderDuplicate(object):
 
 
 @SettingsProvider
-class Provider2(object):
+class Provider2:
     config_settings = [
         ('a.string', StringType),
         ('a.boolean', BooleanType),
@@ -68,7 +64,7 @@ class Provider2(object):
 
 
 @SettingsProvider
-class Provider3(object):
+class Provider3:
     @classmethod
     def config_settings(cls):
         return [
@@ -81,7 +77,7 @@ class Provider3(object):
 
 
 @SettingsProvider
-class Provider4(object):
+class Provider4:
     config_settings = [
         ('foo.abc', StringType, 'a', {'choices': set('abc')}),
         ('foo.xyz', StringType, 'w', {'choices': set('xyz')}),
@@ -89,7 +85,7 @@ class Provider4(object):
 
 
 @SettingsProvider
-class Provider5(object):
+class Provider5:
     config_settings = [
         ('foo.*', 'string'),
         ('foo.bar', 'string'),
diff --git a/python/mach/mach/test/test_dispatcher.py b/python/mach/mach/test/test_dispatcher.py
index 3d689a4a20..01b2412336 100644
--- a/python/mach/mach/test/test_dispatcher.py
+++ b/python/mach/mach/test/test_dispatcher.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 from cStringIO import StringIO
@@ -26,7 +25,7 @@ class TestDispatcher(TestBase):
             mach.settings.register_provider(provider)
 
         if config:
-            if isinstance(config, basestring):
+            if isinstance(config, str):
                 config = StringIO(config)
             mach.settings.load_fps([config])
 
@@ -44,11 +43,11 @@ cmd_bar = cmd_bar --baz
         parser = self.get_parser(config=config)
 
         args = parser.parse_args(['foo'])
-        self.assertEquals(args.command, 'cmd_foo')
+        self.assertEqual(args.command, 'cmd_foo')
 
         def assert_bar_baz(argv):
             args = parser.parse_args(argv)
-            self.assertEquals(args.command, 'cmd_bar')
+            self.assertEqual(args.command, 'cmd_bar')
             self.assertTrue(args.command_args.baz)
 
         # The following should all result in |cmd_bar --baz|
diff --git a/python/mach/mach/test/test_entry_point.py b/python/mach/mach/test/test_entry_point.py
index 7aea91e5e4..34eac232bf 100644
--- a/python/mach/mach/test/test_entry_point.py
+++ b/python/mach/mach/test/test_entry_point.py
@@ -1,7 +1,6 @@
 # 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 unicode_literals
 
 import imp
 import os
@@ -9,7 +8,7 @@ import sys
 
 from mach.base import MachError
 from mach.test.common import TestBase
-from mock import patch
+from unittest.mock import patch
 
 from mozunit import main
 
diff --git a/python/mach/mach/test/test_error_output.py b/python/mach/mach/test/test_error_output.py
index 25553f96bc..58e3d032ea 100644
--- a/python/mach/mach/test/test_error_output.py
+++ b/python/mach/mach/test/test_error_output.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from mach.main import (
     COMMAND_ERROR,
diff --git a/python/mach/mach/test/test_logger.py b/python/mach/mach/test/test_logger.py
index 05592845e7..6eb6036f14 100644
--- a/python/mach/mach/test/test_logger.py
+++ b/python/mach/mach/test/test_logger.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import logging
 import time
diff --git a/python/mach_commands.py b/python/mach_commands.py
index 5ff0b1876e..98a78056b0 100644
--- a/python/mach_commands.py
+++ b/python/mach_commands.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import __main__
 import argparse
@@ -36,7 +35,7 @@ class MachCommands(MachCommandBase):
             pass_thru=True,  # Allow user to run Python interactively.
             ensure_exit_code=False,  # Don't throw on non-zero exit code.
             # Note: subprocess requires native strings in os.environ on Windows
-            append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
+            append_env={b'PYTHONDONTWRITEBYTECODE': '1'})
 
     @Command('python-test', category='testing',
         description='Run Python unit tests with an appropriate test runner.')
@@ -130,7 +129,7 @@ class MachCommands(MachCommandBase):
                 ensure_exit_code=False,  # Don't throw on non-zero exit code.
                 log_name='python-test',
                 # subprocess requires native strings in os.environ on Windows
-                append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
+                append_env={b'PYTHONDONTWRITEBYTECODE': '1'},
                 line_handler=_line_handler)
             return_code += inner_return_code
 
diff --git a/python/macholib/doc/conf.py b/python/macholib/doc/conf.py
index 08a48f3ede..15cb669f18 100644
--- a/python/macholib/doc/conf.py
+++ b/python/macholib/doc/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # macholib documentation build configuration file, created by
 # sphinx-quickstart on Tue Sep 28 22:23:35 2010.
@@ -52,8 +51,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'macholib'
-copyright = u'2010-2011, Ronald Oussoren'
+project = 'macholib'
+copyright = '2010-2011, Ronald Oussoren'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -190,8 +189,8 @@ htmlhelp_basename = 'macholibdoc'
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-  ('index', 'macholib.tex', u'macholib Documentation',
-   u'Ronald Oussoren', 'manual'),
+  ('index', 'macholib.tex', 'macholib Documentation',
+   'Ronald Oussoren', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -223,18 +222,18 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'macholib', u'macholib Documentation',
-     [u'Ronald Oussoren'], 1)
+    ('index', 'macholib', 'macholib Documentation',
+     ['Ronald Oussoren'], 1)
 ]
 
 
 # -- Options for Epub output ---------------------------------------------------
 
 # Bibliographic Dublin Core info.
-epub_title = u'macholib'
-epub_author = u'Ronald Oussoren'
-epub_publisher = u'Ronald Oussoren'
-epub_copyright = u'2010, Ronald Oussoren'
+epub_title = 'macholib'
+epub_author = 'Ronald Oussoren'
+epub_publisher = 'Ronald Oussoren'
+epub_copyright = '2010, Ronald Oussoren'
 
 # The language of the text. It defaults to the language option
 # or en if the language is not set.
diff --git a/python/macholib/macholib/MachO.py b/python/macholib/macholib/MachO.py
index f83ddb7115..b227d9ab04 100644
--- a/python/macholib/macholib/MachO.py
+++ b/python/macholib/macholib/MachO.py
@@ -1,8 +1,8 @@
 """
 Utilities for reading and writing Mach-O headers
 """
-from __future__ import print_function
 
+from __future__ import print_function
 import sys
 import struct
 
@@ -15,19 +15,19 @@ except ImportError:
     pass
 
 try:
-    unicode
+    str
 except NameError:
-    unicode = str
+    str = str
 
 __all__ = ['MachO']
 
-_RELOCATABLE = set((
+_RELOCATABLE = {
     # relocatable commands that should be used for dependency walking
     LC_LOAD_DYLIB,
     LC_LOAD_WEAK_DYLIB,
     LC_PREBOUND_DYLIB,
     LC_REEXPORT_DYLIB,
-))
+}
 
 _RELOCATABLE_NAMES = {
     LC_LOAD_DYLIB: 'load_dylib',
@@ -42,7 +42,7 @@ def _shouldRelocateCommand(cmd):
     """
     return cmd in _RELOCATABLE
 
-class MachO(object):
+class MachO:
     """
     Provides reading/writing the Mach-O header of a specific existing file
     """
@@ -69,7 +69,7 @@ class MachO(object):
             self.load(fp)
 
     def __repr__(self):
-        return "<MachO filename=%r>" % (self.filename,)
+        return "<MachO filename={!r}>".format(self.filename)
 
     def load(self, fh):
         assert fh.tell() == 0
@@ -109,7 +109,7 @@ class MachO(object):
         elif header == MH_CIGAM_64:
             magic, hdr, endian = MH_CIGAM_64, mach_header_64, '<'
         else:
-            raise ValueError("Unknown Mach-O header: 0x%08x in %r" % (
+            raise ValueError("Unknown Mach-O header: 0x{:08x} in {!r}".format(
                 header, fh))
         hdr = MachOHeader(self, fh, offset, size, magic, hdr, endian)
         self.headers.append(hdr)
@@ -118,7 +118,7 @@ class MachO(object):
         for header in self.headers:
             header.write(f)
 
-class MachOHeader(object):
+class MachOHeader:
     """
     Provides reading/writing the Mach-O header of a specific existing file
     """
@@ -287,7 +287,7 @@ class MachOHeader(object):
     def changedHeaderSizeBy(self, bytes):
         self.sizediff += bytes
         if (self.total_size + self.sizediff) > self.low_offset:
-            print("WARNING: Mach-O header in %r may be too large to relocate"%(self.parent.filename,))
+            print(("WARNING: Mach-O header in %r may be too large to relocate"%(self.parent.filename,)))
 
     def rewriteLoadCommands(self, changefunc):
         """
@@ -338,7 +338,7 @@ class MachOHeader(object):
             cmd.to_fileobj(fileobj)
 
             if sys.version_info[0] == 2:
-                if isinstance(data, unicode):
+                if isinstance(data, str):
                     fileobj.write(data.encode(sys.getfilesystemencoding()))
 
                 elif isinstance(data, (bytes, str)):
@@ -388,7 +388,7 @@ def main(fn):
         for idx, name, other in header.walkRelocatables():
             if other not in seen:
                 seen.add(other)
-                print('\t' + name + ": " + other)
+                print(('\t' + name + ": " + other))
 
 if __name__ == '__main__':
     import sys
diff --git a/python/macholib/macholib/MachOGraph.py b/python/macholib/macholib/MachOGraph.py
index 8875c56eb5..45317e5bcb 100644
--- a/python/macholib/macholib/MachOGraph.py
+++ b/python/macholib/macholib/MachOGraph.py
@@ -16,30 +16,30 @@ from macholib.itergraphreport import itergraphreport
 __all__ = ['MachOGraph']
 
 try:
-    unicode
+    str
 except NameError:
-    unicode = str
+    str = str
 
-class MissingMachO(object):
+class MissingMachO:
     def __init__(self, filename):
         self.graphident = filename
         self.headers = ()
 
     def __repr__(self):
-        return '<%s graphident=%r>' % (type(self).__name__, self.graphident)
+        return '<{} graphident={!r}>'.format(type(self).__name__, self.graphident)
 
 class MachOGraph(ObjectGraph):
     """
     Graph data structure of Mach-O dependencies
     """
     def __init__(self, debug=0, graph=None, env=None, executable_path=None):
-        super(MachOGraph, self).__init__(debug=debug, graph=graph)
+        super().__init__(debug=debug, graph=graph)
         self.env = env
         self.trans_table = {}
         self.executable_path = executable_path
 
     def locate(self, filename, loader=None):
-        assert isinstance(filename, (str, unicode))
+        assert isinstance(filename, (str, str))
         if filename.startswith('@loader_path/') and loader is not None:
             fn = self.trans_table.get((loader.filename, filename))
             if fn is None:
@@ -63,8 +63,8 @@ class MachOGraph(ObjectGraph):
         return fn
 
     def findNode(self, name, loader=None):
-        assert isinstance(name, (str, unicode))
-        data = super(MachOGraph, self).findNode(name)
+        assert isinstance(name, (str, str))
+        data = super().findNode(name)
         if data is not None:
             return data
         newname = self.locate(name, loader=loader)
@@ -73,12 +73,12 @@ class MachOGraph(ObjectGraph):
         return None
 
     def run_file(self, pathname, caller=None):
-        assert isinstance(pathname, (str, unicode))
+        assert isinstance(pathname, (str, str))
         self.msgin(2, "run_file", pathname)
         m = self.findNode(pathname, loader=caller)
         if m is None:
             if not os.path.exists(pathname):
-                raise ValueError('%r does not exist' % (pathname,))
+                raise ValueError('{!r} does not exist'.format(pathname))
             m = self.createNode(MachO, pathname)
             self.createReference(caller, m, edge_data='run_file')
             self.scan_node(m)
@@ -86,7 +86,7 @@ class MachOGraph(ObjectGraph):
         return m
 
     def load_file(self, name, caller=None):
-        assert isinstance(name, (str, unicode))
+        assert isinstance(name, (str, str))
         self.msgin(2, "load_file", name)
         m = self.findNode(name)
         if m is None:
@@ -105,14 +105,14 @@ class MachOGraph(ObjectGraph):
         self.msgin(2, 'scan_node', node)
         for header in node.headers:
             for idx, name, filename in header.walkRelocatables():
-                assert isinstance(name, (str, unicode))
-                assert isinstance(filename, (str, unicode))
+                assert isinstance(name, (str, str))
+                assert isinstance(filename, (str, str))
                 m = self.load_file(filename, caller=node)
                 self.createReference(node, m, edge_data=name)
         self.msgout(2, '', node)
 
     def itergraphreport(self, name='G'):
-        nodes = map(self.graph.describe_node, self.graph.iterdfs(self))
+        nodes = list(map(self.graph.describe_node, self.graph.iterdfs(self)))
         describe_edge = self.graph.describe_edge
         return itergraphreport(nodes, describe_edge, name=name)
 
diff --git a/python/macholib/macholib/MachOStandalone.py b/python/macholib/macholib/MachOStandalone.py
index f8627336ce..85bdc804b3 100644
--- a/python/macholib/macholib/MachOStandalone.py
+++ b/python/macholib/macholib/MachOStandalone.py
@@ -11,21 +11,21 @@ class ExcludedMachO(MissingMachO):
 
 class FilteredMachOGraph(MachOGraph):
     def __init__(self, delegate, *args, **kwargs):
-        super(FilteredMachOGraph, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.delegate = delegate
 
     def createNode(self, cls, name):
         cls = self.delegate.getClass(name, cls)
-        res = super(FilteredMachOGraph, self).createNode(cls, name)
+        res = super().createNode(cls, name)
         return res
 
     def locate(self, filename, loader=None):
-        newname = super(FilteredMachOGraph, self).locate(filename, loader)
+        newname = super().locate(filename, loader)
         if newname is None:
             return None
         return self.delegate.locate(newname)
 
-class MachOStandalone(object):
+class MachOStandalone:
     def __init__(self, base, dest=None, graph=None, env=None,
             executable_path=None):
         self.base = os.path.join(os.path.abspath(base), '')
@@ -144,4 +144,4 @@ class MachOStandalone(object):
                     flipwritable(fn, old_mode)
 
         allfiles = [mm.locate(node.filename) for node in machfiles]
-        return set(filter(None, allfiles))
+        return set([_f for _f in allfiles if _f])
diff --git a/python/macholib/macholib/SymbolTable.py b/python/macholib/macholib/SymbolTable.py
index 62fb172fda..ad4e1b81e7 100644
--- a/python/macholib/macholib/SymbolTable.py
+++ b/python/macholib/macholib/SymbolTable.py
@@ -8,7 +8,7 @@ __all__ = ['SymbolTable']
 
 # XXX: Does not support 64-bit, probably broken anyway
 
-class SymbolTable(object):
+class SymbolTable:
     def __init__(self, macho, openfile=None):
         if openfile is None:
             openfile = open
@@ -30,7 +30,7 @@ class SymbolTable(object):
         strtab = fh.read(cmd.strsize)
         fh.seek(cmd.symoff)
         nlists = []
-        for i in xrange(cmd.nsyms):
+        for i in range(cmd.nsyms):
             cmd = nlist.from_fileobj(fh)
             if cmd.n_un == 0:
                 nlists.append((cmd, ''))
@@ -72,18 +72,18 @@ class SymbolTable(object):
     def readtoc(self, fh, off, n):
         #print 'toc', off, n
         fh.seek(off)
-        return [dylib_table_of_contents.from_fileobj(fh) for i in xrange(n)]
+        return [dylib_table_of_contents.from_fileobj(fh) for i in range(n)]
 
     def readmodtab(self, fh, off, n):
         #print 'modtab', off, n
         fh.seek(off)
-        return [dylib_module.from_fileobj(fh) for i in xrange(n)]
+        return [dylib_module.from_fileobj(fh) for i in range(n)]
 
     def readsym(self, fh, off, n):
         #print 'sym', off, n
         fh.seek(off)
         refs = []
-        for i in xrange(n):
+        for i in range(n):
             ref = dylib_reference.from_fileobj(fh)
             isym, flags = divmod(ref.isym_flags, 256)
             refs.append((self.nlists[isym], flags))
@@ -92,4 +92,4 @@ class SymbolTable(object):
     def readrel(self, fh, off, n):
         #print 'rel', off, n
         fh.seek(off)
-        return [relocation_info.from_fileobj(fh) for i in xrange(n)]
+        return [relocation_info.from_fileobj(fh) for i in range(n)]
diff --git a/python/macholib/macholib/__init__.py b/python/macholib/macholib/__init__.py
index df68ce8025..96a3c92174 100644
--- a/python/macholib/macholib/__init__.py
+++ b/python/macholib/macholib/__init__.py
@@ -5,6 +5,5 @@ See the relevant header files in /usr/include/mach-o
 
 And also Apple's documentation.
 """
-from __future__ import print_function
 import pkg_resources
 __version__ = pkg_resources.require('macholib')[0].version
diff --git a/python/macholib/macholib/__main__.py b/python/macholib/macholib/__main__.py
index 5309872cae..c3c8bac527 100644
--- a/python/macholib/macholib/__main__.py
+++ b/python/macholib/macholib/__main__.py
@@ -1,4 +1,3 @@
-from __future__ import print_function, absolute_import
 import os, sys
 
 from macholib.util import is_platform_file
@@ -9,15 +8,15 @@ gCommand = None
 
 def check_file(fp, path, callback):
     if not os.path.exists(path):
-        print('%s: %s: No such file or directory' % (gCommand, path),
+        print('{}: {}: No such file or directory'.format(gCommand, path),
                 file=sys.stderr)
         return 1
 
     try:
         is_plat = is_platform_file(path)
 
-    except IOError as msg:
-        print('%s: %s: %s' % (gCommand, path, msg), file=sys.stderr)
+    except OSError as msg:
+        print('{}: {}: {}'.format(gCommand, path, msg), file=sys.stderr)
         return 1
 
     else:
diff --git a/python/macholib/macholib/_cmdline.py b/python/macholib/macholib/_cmdline.py
index eb44824f99..bcafa67a87 100644
--- a/python/macholib/macholib/_cmdline.py
+++ b/python/macholib/macholib/_cmdline.py
@@ -1,7 +1,6 @@
 """
 Internal helpers for basic commandline tools
 """
-from __future__ import print_function, absolute_import
 import os
 import sys
 
@@ -9,14 +8,14 @@ from macholib.util import is_platform_file
 
 def check_file(fp, path, callback):
     if not os.path.exists(path):
-        print('%s: %s: No such file or directory' % (sys.argv[0], path), file=sys.stderr)
+        print('{}: {}: No such file or directory'.format(sys.argv[0], path), file=sys.stderr)
         return 1
 
     try:
         is_plat = is_platform_file(path)
 
-    except IOError as msg:
-        print('%s: %s: %s' % (sys.argv[0], path, msg), file=sys.stderr)
+    except OSError as msg:
+        print('{}: {}: {}'.format(sys.argv[0], path, msg), file=sys.stderr)
         return 1
 
     else:
diff --git a/python/macholib/macholib/dyld.py b/python/macholib/macholib/dyld.py
index 2e81db7f88..95bdab8159 100644
--- a/python/macholib/macholib/dyld.py
+++ b/python/macholib/macholib/dyld.py
@@ -31,17 +31,10 @@ _DEFAULT_LIBRARY_FALLBACK = [
 ]
 
 # XXX: Is this function still needed?
-if sys.version_info[0] == 2:
-    def _ensure_utf8(s):
-        """Not all of PyObjC and Python understand unicode paths very well yet"""
-        if isinstance(s, unicode):
-            return s.encode('utf8')
-        return s
-else:
-    def _ensure_utf8(s):
-        if s is not None and not isinstance(s, str):
-            raise ValueError(s)
-        return s
+def _ensure_utf8(s):
+    if s is not None and not isinstance(s, str):
+        raise ValueError(s)
+    return s
 
 
 def _dyld_env(env, var):
@@ -153,7 +146,7 @@ def dyld_find(name, executable_path=None, env=None, loader_path=None):
             ), env):
         if os.path.isfile(path):
             return path
-    raise ValueError("dylib %s could not be found" % (name,))
+    raise ValueError("dylib {} could not be found".format(name))
 
 def framework_find(fn, executable_path=None, env=None):
     """
diff --git a/python/macholib/macholib/itergraphreport.py b/python/macholib/macholib/itergraphreport.py
index 453c96e2ac..d886b47256 100644
--- a/python/macholib/macholib/itergraphreport.py
+++ b/python/macholib/macholib/itergraphreport.py
@@ -7,7 +7,7 @@ XXX: need to rewrite this based on altgraph.Dot
 from collections import deque
 
 try:
-    from itertools import imap
+    
 except ImportError:
     imap = map
 
@@ -24,11 +24,11 @@ def itergraphreport(nodes, describe_edge, name='G'):
     def edgevisitor(edge, data, head, tail):
         return {}
 
-    yield 'digraph %s {\n' % (name,)
+    yield 'digraph {} {{\n'.format(name)
     attr = dict(rankdir='LR', concentrate='true')
     cpatt  = '%s="%s"'
-    for item in attr.iteritems():
-        yield '\t%s;\n' % (cpatt % item,)
+    for item in attr.items():
+        yield '\t{};\n'.format(cpatt % item)
 
     # find all packages (subgraphs)
     for (node, data, outgoing, incoming) in nodes:
@@ -37,15 +37,15 @@ def itergraphreport(nodes, describe_edge, name='G'):
     # create sets for subgraph, write out descriptions
     for (node, data, outgoing, incoming) in nodes:
         # update edges
-        for edge in imap(describe_edge, outgoing):
+        for edge in map(describe_edge, outgoing):
             edges.append(edge)
 
         # describe node
-        yield '\t"%s" [%s];\n' % (
+        yield '\t"{}" [{}];\n'.format(
             node,
             ','.join([
                 (cpatt % item) for item in
-                nodevisitor(node, data, outgoing, incoming).iteritems()
+                nodevisitor(node, data, outgoing, incoming.items())
             ]),
         )
 
@@ -64,10 +64,9 @@ def itergraphreport(nodes, describe_edge, name='G'):
             yield edgestr % (
                 head,
                 tail,
-                ','.join([(cpatt % item) for item in attribs.iteritems()]),
+                ','.join([(cpatt % item) for item in attribs.items()]),
             )
 
-    for s in do_graph(graph, '\t'):
-        yield s
+    yield from do_graph(graph, '\t')
 
     yield '}\n'
diff --git a/python/macholib/macholib/mach_o.py b/python/macholib/macholib/mach_o.py
index 1a85c75cf7..8c931d3dbd 100644
--- a/python/macholib/macholib/mach_o.py
+++ b/python/macholib/macholib/mach_o.py
@@ -201,7 +201,7 @@ MH_DYLINKER_SYM = "_mh_dylinker_header"
 (
     MH_OBJECT, MH_EXECUTE, MH_FVMLIB, MH_CORE, MH_PRELOAD, MH_DYLIB,
     MH_DYLINKER, MH_BUNDLE, MH_DYLIB_STUB, MH_DSYM
-) = range(0x1, 0xb)
+) = list(range(0x1, 0xb))
 
 (
     MH_NOUNDEFS, MH_INCRLINK, MH_DYLDLINK, MH_BINDATLOAD, MH_PREBOUND,
@@ -210,7 +210,7 @@ MH_DYLINKER_SYM = "_mh_dylinker_header"
     MH_CANONICAL, MH_WEAK_DEFINES, MH_BINDS_TO_WEAK, MH_ALLOW_STACK_EXECUTION,
     MH_ROOT_SAFE, MH_SETUID_SAFE, MH_NO_REEXPORTED_DYLIBS, MH_PIE,
     MH_DEAD_STRIPPABLE_DYLIB, MH_HAS_TLV_DESCRIPTORS, MH_NO_HEAP_EXECUTION
-) = map((1).__lshift__, range(25))
+) = list(map((1).__lshift__, list(range(25))))
 
 MH_MAGIC = 0xfeedface
 MH_CIGAM = 0xcefaedfe
@@ -310,7 +310,7 @@ class mach_version_helper(Structure):
         ('rev', p_uint8),
     )
     def __str__(self):
-        return '%s.%s.%s' % (self.major, self.minor, self.rev)
+        return '{}.{}.{}'.format(self.major, self.minor, self.rev)
 
 class mach_timestamp_helper(p_uint32):
     def __str__(self):
@@ -372,7 +372,7 @@ LC_REQ_DYLD = 0x80000000
     LC_ID_DYLIB, LC_LOAD_DYLINKER, LC_ID_DYLINKER, LC_PREBOUND_DYLIB,
     LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT,
     LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM
-) = range(0x1, 0x18)
+) = list(range(0x1, 0x18))
 
 LC_LOAD_WEAK_DYLIB = LC_REQ_DYLD | 0x18
 
@@ -1282,7 +1282,7 @@ def GET_LIBRARY_ORDINAL(n_desc):
     return (((n_desc) >> 8) & 0xff)
 
 def SET_LIBRARY_ORDINAL(n_desc, ordinal):
-    return (((n_desc) & 0x00ff) | (((ordinal & 0xff) << 8)))
+    return (((n_desc) & 0x00ff) | ((ordinal & 0xff) << 8))
 
 SELF_LIBRARY_ORDINAL = 0x0
 MAX_LIBRARY_ORDINAL = 0xfd
diff --git a/python/macholib/macholib/macho_dump.py b/python/macholib/macholib/macho_dump.py
index 737ce8ebeb..55d35e74b6 100644
--- a/python/macholib/macholib/macho_dump.py
+++ b/python/macholib/macholib/macho_dump.py
@@ -1,6 +1,5 @@
 #!/usr/bin/env python
 
-from __future__ import print_function
 
 import os
 import sys
@@ -29,7 +28,7 @@ def print_file(fp, path):
         arch = CPU_TYPE_NAMES.get(header.header.cputype,
                 header.header.cputype)
 
-        print('    [%s endian=%r size=%r arch=%r]' % (header.__class__.__name__,
+        print('    [{} endian={!r} size={!r} arch={!r}]'.format(header.__class__.__name__,
                 header.endian, sz, arch), file=fp)
         for idx, name, other in header.walkRelocatables():
             if other not in seen:
diff --git a/python/macholib/macholib/macho_find.py b/python/macholib/macholib/macho_find.py
index 0a0cef270b..4ad33c2419 100644
--- a/python/macholib/macholib/macho_find.py
+++ b/python/macholib/macholib/macho_find.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-from __future__ import print_function
 from macholib._cmdline import main as _main
 
 
diff --git a/python/macholib/macholib/macho_standalone.py b/python/macholib/macholib/macho_standalone.py
index ceec82bc96..f7fec5278c 100644
--- a/python/macholib/macholib/macho_standalone.py
+++ b/python/macholib/macholib/macho_standalone.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os
 import sys
 
@@ -9,8 +10,8 @@ from macholib.util import strip_files
 def standaloneApp(path):
     if not (os.path.isdir(path) and os.path.exists(
             os.path.join(path, 'Contents'))):
-        print('%s: %s does not look like an app bundle'
-            % (sys.argv[0], path))
+        print(('%s: %s does not look like an app bundle'
+            % (sys.argv[0], path)))
         sys.exit(1)
     files = MachOStandalone(path).run()
     strip_files(files)
@@ -18,7 +19,7 @@ def standaloneApp(path):
 def main():
     print("WARNING: 'macho_standalone' is deprecated, use 'python -mmacholib standalone' instead")
     if not sys.argv[1:]:
-        raise SystemExit('usage: %s [appbundle ...]' % (sys.argv[0],))
+        raise SystemExit('usage: {} [appbundle ...]'.format(sys.argv[0]))
     for fn in sys.argv[1:]:
         standaloneApp(fn)
 
diff --git a/python/macholib/macholib/ptypes.py b/python/macholib/macholib/ptypes.py
index f1457c91bb..ae51e8aa30 100644
--- a/python/macholib/macholib/ptypes.py
+++ b/python/macholib/macholib/ptypes.py
@@ -6,7 +6,7 @@ import struct
 import sys
 
 try:
-    from itertools import izip, imap
+    
 except ImportError:
     izip, imap = zip, map
 from itertools import chain, starmap
@@ -69,7 +69,7 @@ class MetaPackable(type):
     def from_tuple(cls, tpl, **kw):
         return cls(tpl[0], **kw)
 
-class BasePackable(object):
+class BasePackable:
     _endian_ = '>'
 
     def to_str(self):
@@ -156,7 +156,7 @@ class MetaStructure(MetaPackable):
         dct['_size_'] = size
         dct['_items_'] = items
         dct['_format_'] = format
-        return super(MetaStructure, cls).__new__(cls, clsname, bases, dct)
+        return super().__new__(cls, clsname, bases, dct)
 
     def from_tuple(cls, tpl, **kw):
         values = []
@@ -183,18 +183,18 @@ def _make():
             kwargs = args[0]._objects_
             args = ()
         self._objects_ = {}
-        iargs = chain(izip(self._names_, args), kwargs.items())
+        iargs = chain(zip(self._names_, args), list(kwargs.items()))
         for key, value in iargs:
             if key not in self._names_ and key != "_endian_":
                 raise TypeError
             setattr(self, key, value)
-        for key, typ in izip(self._names_, self._types_):
+        for key, typ in zip(self._names_, self._types_):
             if key not in self._objects_:
                 self._objects_[key] = typ()
 
     @as_method
     def _get_packables(self):
-        for obj in imap(self._objects_.__getitem__, self._names_):
+        for obj in map(self._objects_.__getitem__, self._names_):
             if obj._items_ == 1:
                 yield obj
             else:
@@ -208,21 +208,18 @@ def _make():
     @as_method
     def __cmp__(self, other):
         if type(other) is not type(self):
-            raise TypeError('Cannot compare objects of type %r to objects of type %r' % (type(other), type(self)))
-        if sys.version_info[0] == 2:
-            _cmp = cmp
-        else:
-            def _cmp(a, b):
-                if a < b:
-                    return -1
-                elif a > b:
-                    return 1
-                elif a == b:
-                    return 0
-                else:
-                    raise TypeError()
-
-        for cmpval in starmap(_cmp, izip(self._get_packables(), other._get_packables())):
+            raise TypeError('Cannot compare objects of type {!r} to objects of type {!r}'.format(type(other), type(self)))
+        def _cmp(a, b):
+            if a < b:
+                return -1
+            elif a > b:
+                return 1
+            elif a == b:
+                return 0
+            else:
+                raise TypeError()
+
+        for cmpval in starmap(_cmp, zip(self._get_packables(), other._get_packables())):
             if cmpval != 0:
                 return cmpval
         return 0
@@ -262,7 +259,7 @@ Structure = _make()
 del _make
 
 try:
-    long
+    int
 except NameError:
     long = int
 
@@ -273,9 +270,9 @@ p_uint8 = pypackable('p_uint8', int, 'B')
 p_int16 = pypackable('p_int16', int, 'h')
 p_uint16 = pypackable('p_uint16', int, 'H')
 p_int32 = pypackable('p_int32', int, 'i')
-p_uint32 = pypackable('p_uint32', long, 'I')
-p_int64 = pypackable('p_int64', long, 'q')
-p_uint64 = pypackable('p_uint64', long, 'Q')
+p_uint32 = pypackable('p_uint32', int, 'I')
+p_int64 = pypackable('p_int64', int, 'q')
+p_uint64 = pypackable('p_uint64', int, 'Q')
 p_float = pypackable('p_float', float, 'f')
 p_double = pypackable('p_double', float, 'd')
 
diff --git a/python/macholib/macholib/util.py b/python/macholib/macholib/util.py
index 7f954b6f78..3d5f4f2b70 100644
--- a/python/macholib/macholib/util.py
+++ b/python/macholib/macholib/util.py
@@ -18,16 +18,16 @@ MAGIC_LEN = 4
 STRIPCMD = ['/usr/bin/strip', '-x', '-S', '-']
 
 try:
-    unicode
+    str
 except NameError:
-    unicode = str
+    str = str
 
 
 def fsencoding(s, encoding=sys.getfilesystemencoding()):
     """
     Ensure the given argument is in filesystem encoding (not unicode)
     """
-    if isinstance(s, unicode):
+    if isinstance(s, str):
         s = s.encode(encoding)
     return s
 
@@ -54,7 +54,7 @@ def flipwritable(fn, mode=None):
     os.chmod(fn, stat.S_IWRITE | old_mode)
     return old_mode
 
-class fileview(object):
+class fileview:
     """
     A proxy for file-like objects that exposes a given view of a file
     """
@@ -73,7 +73,7 @@ class fileview(object):
 
     def _checkwindow(self, seekto, op):
         if not (self._start <= seekto <= self._end):
-            raise IOError("%s to offset %d is outside window [%d, %d]" % (
+            raise OSError("%s to offset %d is outside window [%d, %d]" % (
                 op, seekto, self._start, self._end))
 
     def seek(self, offset, whence=0):
@@ -85,7 +85,7 @@ class fileview(object):
         elif whence == 2:
             seekto += self._end
         else:
-            raise IOError("Invalid whence argument to seek: %r" % (whence,))
+            raise OSError("Invalid whence argument to seek: {!r}".format(whence))
         self._checkwindow(seekto, 'seek')
         self._fileobj.seek(seekto)
 
@@ -121,7 +121,7 @@ def mergetree(src, dst, condition=None, copyfn=mergecopy, srcbase=None):
     dst = fsencoding(dst)
     if srcbase is None:
         srcbase = src
-    names = map(fsencoding, os.listdir(src))
+    names = list(map(fsencoding, os.listdir(src)))
     try:
         os.makedirs(dst)
     except OSError:
@@ -142,10 +142,10 @@ def mergetree(src, dst, condition=None, copyfn=mergecopy, srcbase=None):
                     condition=condition, copyfn=copyfn, srcbase=srcbase)
             else:
                 copyfn(srcname, dstname)
-        except (IOError, os.error) as why:
+        except OSError as why:
             errors.append((srcname, dstname, why))
     if errors:
-        raise IOError(errors)
+        raise OSError(errors)
 
 def sdk_normalize(filename):
     """
diff --git a/python/macholib/macholib_tests/binaries/src/build.py b/python/macholib/macholib_tests/binaries/src/build.py
index e2a179c783..a49dc9c6ca 100644
--- a/python/macholib/macholib_tests/binaries/src/build.py
+++ b/python/macholib/macholib_tests/binaries/src/build.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os, sys
 
 
@@ -14,7 +15,7 @@ class Builder (object):
                 getattr(self, nm)()
 
     def build_executable(self):
-        print "Building plain executable"
+        print("Building plain executable")
         pass
 
 
diff --git a/python/macholib/macholib_tests/test_dyld.py b/python/macholib/macholib_tests/test_dyld.py
index 7b41758d96..79fd092807 100644
--- a/python/macholib/macholib_tests/test_dyld.py
+++ b/python/macholib/macholib_tests/test_dyld.py
@@ -9,7 +9,7 @@ if sys.version_info[:2] <= (2,6):
 else:
     import unittest
 
-class DyldPatcher (object):
+class DyldPatcher :
     def __init__(self):
         self.calls = []
         self.patched = {}
@@ -44,7 +44,7 @@ class TestDyld (unittest.TestCase):
 
     def setUp(self):
         self._environ = os.environ
-        os.environ = dict([(k, os.environ[k]) for k in os.environ if 'DYLD' not in k])
+        os.environ = {k: os.environ[k] for k in os.environ if 'DYLD' not in k}
         self._dyld_env = dyld._dyld_env
         self._dyld_image_suffix = dyld.dyld_image_suffix
 
@@ -53,17 +53,10 @@ class TestDyld (unittest.TestCase):
         dyld.dyld_image_suffix = self._dyld_image_suffix
         os.environ = self._environ
 
-    if sys.version_info[0] == 2:
-        def test_ensure_utf8(self):
-            self.assertEqual(dyld._ensure_utf8("hello"), "hello")
-            self.assertEqual(dyld._ensure_utf8("hello".decode('utf-8')), "hello")
-            self.assertEqual(dyld._ensure_utf8(None), None)
-
-    else:
-        def test_ensure_utf8(self):
-            self.assertEqual(dyld._ensure_utf8("hello"), "hello")
-            self.assertEqual(dyld._ensure_utf8(None), None)
-            self.assertRaises(ValueError, dyld._ensure_utf8, b"hello")
+    def test_ensure_utf8(self):
+        self.assertEqual(dyld._ensure_utf8("hello"), "hello")
+        self.assertEqual(dyld._ensure_utf8(None), None)
+        self.assertRaises(ValueError, dyld._ensure_utf8, b"hello")
 
     def test__dyld_env(self):
         new = os.environ
diff --git a/python/macholib/macholib_tests/test_ptypes.py b/python/macholib/macholib_tests/test_ptypes.py
index f221d37d32..d6fdd328f6 100644
--- a/python/macholib/macholib_tests/test_ptypes.py
+++ b/python/macholib/macholib_tests/test_ptypes.py
@@ -14,7 +14,7 @@ except ImportError:
 import mmap
 
 try:
-    long
+    int
 except NameError:
     long = int
 
@@ -37,7 +37,7 @@ class TestPTypes (unittest.TestCase):
         self.assertRaises(ValueError, ptypes.sizeof, {})
         self.assertRaises(ValueError, ptypes.sizeof, b"foo".decode('ascii'))
 
-        class M (object):
+        class M :
             pass
 
         m = M()
@@ -89,10 +89,10 @@ class TestPTypes (unittest.TestCase):
         self.verifyType(ptypes.p_uint16, 2, int, [1, 400, 65000])
 
         self.verifyType(ptypes.p_int32, 4, int, [1, 400, 2**24, -10, -5000, -2**24])
-        self.verifyType(ptypes.p_uint32, 4, long, [1, 400, 2*31+5, 65000])
+        self.verifyType(ptypes.p_uint32, 4, int, [1, 400, 2*31+5, 65000])
 
-        self.verifyType(ptypes.p_int64, 8, long, [1, 400, 2**43, -10, -5000, -2**43])
-        self.verifyType(ptypes.p_uint64, 8, long, [1, 400, 2*63+5, 65000])
+        self.verifyType(ptypes.p_int64, 8, int, [1, 400, 2**43, -10, -5000, -2**43])
+        self.verifyType(ptypes.p_uint64, 8, int, [1, 400, 2*63+5, 65000])
 
         self.verifyType(ptypes.p_float, 4, float, [1.0, 42.5])
         self.verifyType(ptypes.p_double, 8, float, [1.0, 42.5])
@@ -105,13 +105,13 @@ class TestPTypes (unittest.TestCase):
         self.verifyType(ptypes.p_ushort, 2, int, [1, 400, 65000])
 
         self.verifyType(ptypes.p_int, 4, int, [1, 400, 2**24, -10, -5000, -2**24])
-        self.verifyType(ptypes.p_uint, 4, long, [1, 400, 2*31+5, 65000])
+        self.verifyType(ptypes.p_uint, 4, int, [1, 400, 2*31+5, 65000])
 
         self.verifyType(ptypes.p_long, 4, int, [1, 400, 2**24, -10, -5000, -2**24])
-        self.verifyType(ptypes.p_ulong, 4, long, [1, 400, 2*31+5, 65000])
+        self.verifyType(ptypes.p_ulong, 4, int, [1, 400, 2*31+5, 65000])
 
-        self.verifyType(ptypes.p_longlong, 8, long, [1, 400, 2**43, -10, -5000, -2**43])
-        self.verifyType(ptypes.p_ulonglong, 8, long, [1, 400, 2*63+5, 65000])
+        self.verifyType(ptypes.p_longlong, 8, int, [1, 400, 2**43, -10, -5000, -2**43])
+        self.verifyType(ptypes.p_ulonglong, 8, int, [1, 400, 2*63+5, 65000])
 
 class TestPTypesPrivate (unittest.TestCase):
     # These are tests for functions that aren't part of the public
diff --git a/python/macholib/setup.py b/python/macholib/setup.py
index a1a4cb6eb2..15913a4417 100644
--- a/python/macholib/setup.py
+++ b/python/macholib/setup.py
@@ -15,6 +15,7 @@ Additional functionality:
 
 """
 
+from __future__ import print_function
 import sys
 import os
 import re
@@ -28,7 +29,7 @@ import tarfile
 try:
     import urllib.request as urllib
 except ImportError:
-    import urllib
+    import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 from distutils import log
 try:
     from hashlib import md5
@@ -36,10 +37,7 @@ try:
 except ImportError:
     from md5 import md5
 
-if sys.version_info[0] == 2:
-    from ConfigParser import RawConfigParser, NoOptionError, NoSectionError
-else:
-    from configparser import RawConfigParser, NoOptionError, NoSectionError
+from configparser import RawConfigParser, NoOptionError, NoSectionError
 
 ROOTDIR = os.path.dirname(os.path.abspath(__file__))
 
@@ -226,7 +224,7 @@ def parse_setup_cfg():
     else:
         parts = []
         for nm in v.split():
-            fp = open(nm, 'rU')
+            fp = open(nm)
             parts.append(fp.read())
             fp.close()
 
@@ -295,7 +293,7 @@ try:
 
     def get_pypi_src_download(package):
         url = 'https://pypi.python.org/pypi/%s/json'%(package,)
-        fp = urllib.urlopen(url)
+        fp = six.moves.urllib.request.urlopen(url)
         try:
             try:
                 data = fp.read()
@@ -323,7 +321,7 @@ except ImportError:
 
     def get_pypi_src_download(package):
         url = 'https://pypi.python.org/pypi/%s/json'%(package,)
-        fp = urllib.urlopen(url)
+        fp = six.moves.urllib.request.urlopen(url)
         try:
             try:
                 data = fp.read()
@@ -412,7 +410,7 @@ def _build_egg(egg, tarball, to_dir):
     # returning the result
     log.warn(egg)
     if not os.path.exists(egg):
-        raise IOError('Could not build the egg.')
+        raise OSError('Could not build the egg.')
 
 
 def _do_download(to_dir, packagename=SETUPTOOLS_PACKAGE):
@@ -437,7 +435,7 @@ def download_setuptools(packagename, to_dir):
     try:
         from urllib.request import urlopen
     except ImportError:
-        from urllib2 import urlopen
+        from urllib.request import urlopen
 
     chksum, url = get_pypi_src_download(packagename)
     tgz_name = os.path.basename(url)
@@ -579,11 +577,11 @@ else:
             import shutil
             import zipfile
             import os
-            import urllib
+            import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
             import StringIO
             from base64 import standard_b64encode
-            import httplib
-            import urlparse
+            import six.moves.http_client
+            import six.moves.urllib.parse
 
             # Extract the package name from distutils metadata
             meta = self.distribution.metadata
@@ -611,7 +609,7 @@ else:
                     fullname = os.path.join(toplevel, fn)
                     relname = os.path.relpath(fullname, 'doc/_build/html')
 
-                    print ("%s -> %s"%(fullname, relname))
+                    print(("%s -> %s"%(fullname, relname)))
 
                     zf.write(fullname, relname)
 
@@ -658,13 +656,13 @@ else:
             self.announce("Uploading documentation to %s"%(self.repository,), log.INFO)
 
             schema, netloc, url, params, query, fragments = \
-                    urlparse.urlparse(self.repository)
+                    six.moves.urllib.parse.urlparse(self.repository)
 
 
             if schema == 'http':
-                http = httplib.HTTPConnection(netloc)
+                http = six.moves.http_client.HTTPConnection(netloc)
             elif schema == 'https':
-                http = httplib.HTTPSConnection(netloc)
+                http = six.moves.http_client.HTTPSConnection(netloc)
             else:
                 raise AssertionError("unsupported schema "+schema)
 
@@ -679,22 +677,22 @@ else:
                 http.putheader('Authorization', auth)
                 http.endheaders()
                 http.send(body)
-            except socket.error:
+            except OSError:
                 e = socket.exc_info()[1]
                 self.announce(str(e), log.ERROR)
                 return
 
             r = http.getresponse()
             if r.status in (200, 301):
-                self.announce('Upload succeeded (%s): %s' % (r.status, r.reason),
+                self.announce('Upload succeeded ({}): {}'.format(r.status, r.reason),
                     log.INFO)
             else:
-                self.announce('Upload failed (%s): %s' % (r.status, r.reason),
+                self.announce('Upload failed ({}): {}'.format(r.status, r.reason),
                     log.ERROR)
 
-                print ('-'*75)
-                print (r.read())
-                print ('-'*75)
+                print(('-'*75))
+                print((r.read()))
+                print(('-'*75))
 
 
 def recursiveGlob(root, pathPattern):
@@ -718,7 +716,7 @@ def importExternalTestCases(unittest,
     """
 
     testFiles = recursiveGlob(root, pathPattern)
-    testModules = map(lambda x:x[len(root)+1:-3].replace('/', '.'), testFiles)
+    testModules = [x[len(root)+1:-3].replace('/', '.') for x in testFiles]
     if package is not None:
         testModules = [(package + '.' + m) for m in testModules]
 
@@ -728,7 +726,7 @@ def importExternalTestCases(unittest,
         try:
             module = __import__(modName)
         except ImportError:
-            print("SKIP %s: %s"%(modName, sys.exc_info()[1]))
+            print(("SKIP %s: %s"%(modName, sys.exc_info()[1])))
             continue
 
         if '.' in modName:
@@ -843,7 +841,7 @@ class test (Command):
                 xpass=len(getattr(result, 'expectedSuccesses', [])),
                 skip=len(getattr(result, 'skipped', [])),
             )
-            print("SUMMARY: %s"%(summary,))
+            print(("SUMMARY: %s"%(summary,)))
 
         finally:
             self.remove_from_sys_path()
diff --git a/python/mock-1.0.0/docs/conf.py b/python/mock-1.0.0/docs/conf.py
index 62f0491cca..6ceec605d8 100644
--- a/python/mock-1.0.0/docs/conf.py
+++ b/python/mock-1.0.0/docs/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # Mock documentation build configuration file, created by
 # sphinx-quickstart on Mon Nov 17 18:12:00 2008.
@@ -13,7 +12,7 @@
 
 import sys, os
 sys.path.insert(0, os.path.abspath('..'))
-from mock import __version__
+from unittest.mock import __version__
 
 # If your extensions are in another directory, add it here. If the directory
 # is relative to the documentation root, use os.path.abspath to make it
@@ -65,8 +64,8 @@ source_suffix = '.txt'
 master_doc = 'index'
 
 # General substitutions.
-project = u'Mock'
-copyright = u'2007-2012, Michael Foord & the mock team'
+project = 'Mock'
+copyright = '2007-2012, Michael Foord & the mock team'
 
 # The default replacements for |version| and |release|, also used in various
 # other places throughout the built documents.
@@ -187,8 +186,8 @@ latex_font_size = '12pt'
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, document class [howto/manual]).
 latex_documents = [
-  ('index', 'Mock.tex', u'Mock Documentation',
-   u'Michael Foord', 'manual'),
+  ('index', 'Mock.tex', 'Mock Documentation',
+   'Michael Foord', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
diff --git a/python/mock-1.0.0/mock.py b/python/mock-1.0.0/mock.py
index 1be4e6e458..171f26978e 100644
--- a/python/mock-1.0.0/mock.py
+++ b/python/mock-1.0.0/mock.py
@@ -56,13 +56,13 @@ except ImportError:
         return inner
 
 try:
-    unicode
+    str
 except NameError:
     # Python 3
-    basestring = unicode = str
+    str = str = str
 
 try:
-    long
+    int
 except NameError:
     # Python 3
     long = int
@@ -77,7 +77,7 @@ try:
     next
 except NameError:
     def next(obj):
-        return obj.next()
+        return next(obj)
 
 
 BaseExceptions = (BaseException,)
@@ -127,7 +127,7 @@ def _is_exception(obj):
     )
 
 
-class _slotted(object):
+class _slotted:
     __slots__ = ['a']
 
 
@@ -209,7 +209,7 @@ def _copy_func_details(func, funcopy):
     #funcopy.__dict__.update(func.__dict__)
     funcopy.__module__ = func.__module__
     if not inPy3k:
-        funcopy.func_defaults = func.func_defaults
+        funcopy.__defaults__ = func.__defaults__
         return
     funcopy.__defaults__ = func.__defaults__
     funcopy.__kwdefaults__ = func.__kwdefaults__
@@ -326,7 +326,7 @@ def _is_magic(name):
     return '__%s__' % name[2:-2] == name
 
 
-class _SentinelObject(object):
+class _SentinelObject:
     "A unique, named, sentinel object."
     def __init__(self, name):
         self.name = name
@@ -335,7 +335,7 @@ class _SentinelObject(object):
         return 'sentinel.%s' % self.name
 
 
-class _Sentinel(object):
+class _Sentinel:
     """Access attributes to return a named object, usable as a sentinel."""
     def __init__(self):
         self._sentinels = {}
@@ -369,13 +369,11 @@ ClassTypes = (type,)
 if not inPy3k:
     ClassTypes = (type, ClassType)
 
-_allowed_names = set(
-    [
+_allowed_names = {
         'return_value', '_mock_return_value', 'side_effect',
         '_mock_side_effect', '_mock_parent', '_mock_new_parent',
         '_mock_name', '_mock_new_name'
-    ]
-)
+}
 
 
 def _delegating_property(name):
@@ -443,7 +441,7 @@ def _check_and_set_parent(parent, value, name, new_name):
 
 
 
-class Base(object):
+class Base:
     _mock_return_value = DEFAULT
     _mock_side_effect = None
     def __init__(self, *args, **kwargs):
@@ -626,7 +624,7 @@ class NonCallableMock(Base):
 
         >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
         >>> mock.configure_mock(**attrs)"""
-        for arg, val in sorted(kwargs.items(),
+        for arg, val in sorted(list(kwargs.items()),
                                # we sort on the number of dots so that
                                # attributes are set before we set attributes on
                                # attributes
@@ -716,7 +714,7 @@ class NonCallableMock(Base):
             if self._spec_set:
                 spec_string = ' spec_set=%r'
             spec_string = spec_string % self._spec_class.__name__
-        return "<%s%s%s id='%s'>" % (
+        return "<{}{}{} id='{}'>".format(
             type(self).__name__,
             name_string,
             spec_string,
@@ -817,7 +815,7 @@ class NonCallableMock(Base):
         self = _mock_self
         if self.call_args is None:
             expected = self._format_mock_call_signature(args, kwargs)
-            raise AssertionError('Expected call: %s\nNot called' % (expected,))
+            raise AssertionError('Expected call: {}\nNot called'.format(expected))
 
         if self.call_args != (args, kwargs):
             msg = self._format_mock_failure_message(args, kwargs)
@@ -863,7 +861,7 @@ class NonCallableMock(Base):
                 not_found.append(kall)
         if not_found:
             raise AssertionError(
-                '%r not all found in call list' % (tuple(not_found),)
+                '{!r} not all found in call list'.format(tuple(not_found))
             )
 
 
@@ -1097,7 +1095,7 @@ def _is_started(patcher):
     return hasattr(patcher, 'is_local')
 
 
-class _patch(object):
+class _patch:
 
     attribute_name = None
     _active_patches = set()
@@ -1207,7 +1205,7 @@ class _patch(object):
             # not in Python 3
             patched.compat_co_firstlineno = getattr(
                 func, "compat_co_firstlineno",
-                func.func_code.co_firstlineno
+                func.__code__.co_firstlineno
             )
         return patched
 
@@ -1228,7 +1226,7 @@ class _patch(object):
 
         if not self.create and original is DEFAULT:
             raise AttributeError(
-                "%s does not have the attribute %r" % (target, name)
+                "{} does not have the attribute {!r}".format(target, name)
             )
         return original, local
 
@@ -1454,7 +1452,7 @@ def _patch_multiple(target, spec=None, create=False, spec_set=None,
     When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX`
     for choosing which methods to wrap.
     """
-    if type(target) in (unicode, str):
+    if type(target) in (str, str):
         getter = lambda: _importer(target)
     else:
         getter = lambda: target
@@ -1557,7 +1555,7 @@ def patch(
     )
 
 
-class _patch_dict(object):
+class _patch_dict:
     """
     Patch a dictionary, or dictionary like object, and restore the dictionary
     to its original state after the test.
@@ -1587,7 +1585,7 @@ class _patch_dict(object):
     """
 
     def __init__(self, in_dict, values=(), clear=False, **kwargs):
-        if isinstance(in_dict, basestring):
+        if isinstance(in_dict, str):
             in_dict = _importer(in_dict)
         self.in_dict = in_dict
         # support any argument supported by dict(...) constructor
@@ -1720,13 +1718,13 @@ else:
 # (as they are metaclass methods)
 # __del__ is not supported at all as it causes problems if it exists
 
-_non_defaults = set('__%s__' % method for method in [
+_non_defaults = {'__%s__' % method for method in [
     'cmp', 'getslice', 'setslice', 'coerce', 'subclasses',
     'format', 'get', 'set', 'delete', 'reversed',
     'missing', 'reduce', 'reduce_ex', 'getinitargs',
     'getnewargs', 'getstate', 'setstate', 'getformat',
     'setformat', 'repr', 'dir'
-])
+]}
 
 
 def _get_method(name, func):
@@ -1737,25 +1735,25 @@ def _get_method(name, func):
     return method
 
 
-_magics = set(
+_magics = {
     '__%s__' % method for method in
     ' '.join([magic_methods, numerics, inplace, right, extra]).split()
-)
+}
 
 _all_magics = _magics | _non_defaults
 
-_unsupported_magics = set([
+_unsupported_magics = {
     '__getattr__', '__setattr__',
     '__init__', '__new__', '__prepare__'
     '__instancecheck__', '__subclasscheck__',
     '__del__'
-])
+}
 
 _calculate_return_value = {
     '__hash__': lambda self: object.__hash__(self),
     '__str__': lambda self: object.__str__(self),
     '__sizeof__': lambda self: object.__sizeof__(self),
-    '__unicode__': lambda self: unicode(object.__str__(self)),
+    '__unicode__': lambda self: str(object.__str__(self)),
 }
 
 _return_values = {
@@ -1773,7 +1771,7 @@ _return_values = {
     '__nonzero__': True,
     '__oct__': '1',
     '__hex__': '0x1',
-    '__long__': long(1),
+    '__long__': int(1),
     '__index__': 1,
 }
 
@@ -1834,7 +1832,7 @@ def _set_return_value(mock, method, name):
 
 
 
-class MagicMixin(object):
+class MagicMixin:
     def __init__(self, *args, **kw):
         _super(MagicMixin, self).__init__(*args, **kw)
         self._mock_set_magics()
@@ -1898,7 +1896,7 @@ class MagicMock(MagicMixin, Mock):
 
 
 
-class MagicProxy(object):
+class MagicProxy:
     def __init__(self, name, parent):
         self.name = name
         self.parent = parent
@@ -1921,7 +1919,7 @@ class MagicProxy(object):
 
 
 
-class _ANY(object):
+class _ANY:
     "A helper object that compares equal to everything."
 
     def __eq__(self, other):
@@ -1942,7 +1940,7 @@ def _format_call_signature(name, args, kwargs):
     formatted_args = ''
     args_string = ', '.join([repr(arg) for arg in args])
     kwargs_string = ', '.join([
-        '%s=%r' % (key, value) for key, value in kwargs.items()
+        '{}={!r}'.format(key, value) for key, value in kwargs.items()
     ])
     if args_string:
         formatted_args = args_string
@@ -1984,7 +1982,7 @@ class _Call(tuple):
             name, args, kwargs = value
         elif _len == 2:
             first, second = value
-            if isinstance(first, basestring):
+            if isinstance(first, str):
                 name = first
                 if isinstance(second, tuple):
                     args = second
@@ -1994,7 +1992,7 @@ class _Call(tuple):
                 args, kwargs = first, second
         elif _len == 1:
             value, = value
-            if isinstance(value, basestring):
+            if isinstance(value, str):
                 name = value
             elif isinstance(value, tuple):
                 args = value
@@ -2038,7 +2036,7 @@ class _Call(tuple):
             if isinstance(value, tuple):
                 other_args = value
                 other_kwargs = {}
-            elif isinstance(value, basestring):
+            elif isinstance(value, str):
                 other_name = value
                 other_args, other_kwargs = (), {}
             else:
@@ -2048,7 +2046,7 @@ class _Call(tuple):
             # len 2
             # could be (name, args) or (name, kwargs) or (args, kwargs)
             first, second = other
-            if isinstance(first, basestring):
+            if isinstance(first, str):
                 other_name = first
                 if isinstance(second, tuple):
                     other_args, other_kwargs = second, {}
@@ -2079,7 +2077,7 @@ class _Call(tuple):
     def __getattr__(self, attr):
         if self.name is None:
             return _Call(name=attr, from_kall=False)
-        name = '%s.%s' % (self.name, attr)
+        name = '{}.{}'.format(self.name, attr)
         return _Call(name=name, parent=self, from_kall=False)
 
 
@@ -2221,7 +2219,7 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
         else:
             parent = mock
             if isinstance(spec, FunctionTypes):
-                parent = mock.mock
+                parent = mock
 
             new = MagicMock(parent=parent, name=entry, _new_name=entry,
                             _new_parent=parent, **kwargs)
@@ -2270,7 +2268,7 @@ def _get_class(obj):
         return type(obj)
 
 
-class _SpecState(object):
+class _SpecState:
 
     def __init__(self, spec, spec_set=False, parent=None,
                  name=None, ids=None, instance=False):
@@ -2291,7 +2289,7 @@ FunctionTypes = (
     type(_ANY.__eq__),
 )
 
-FunctionAttributes = set([
+FunctionAttributes = {
     'func_closure',
     'func_code',
     'func_defaults',
@@ -2299,7 +2297,7 @@ FunctionAttributes = set([
     'func_doc',
     'func_globals',
     'func_name',
-])
+}
 
 
 file_spec = None
diff --git a/python/mock-1.0.0/setup.py b/python/mock-1.0.0/setup.py
index 7c25e8f2dd..02c563da4e 100755
--- a/python/mock-1.0.0/setup.py
+++ b/python/mock-1.0.0/setup.py
@@ -4,7 +4,7 @@
 # E-mail: fuzzyman AT voidspace DOT org DOT uk
 # http://www.voidspace.org.uk/python/mock/
 
-from mock import __version__
+from unittest.mock import __version__
 
 import os
 
diff --git a/python/mock-1.0.0/tests/_testwith.py b/python/mock-1.0.0/tests/_testwith.py
index 0b54780b80..6df8accffa 100644
--- a/python/mock-1.0.0/tests/_testwith.py
+++ b/python/mock-1.0.0/tests/_testwith.py
@@ -2,11 +2,10 @@
 # E-mail: fuzzyman AT voidspace DOT org DOT uk
 # http://www.voidspace.org.uk/python/mock/
 
-from __future__ import with_statement
 
 from tests.support import unittest2, is_instance
 
-from mock import MagicMock, Mock, patch, sentinel, mock_open, call
+from unittest.mock import MagicMock, Mock, patch, sentinel, mock_open, call
 
 from tests.support_with import catch_warnings, nested
 
@@ -44,7 +43,7 @@ class WithTest(unittest2.TestCase):
 
 
     def test_patch_object_with_statement(self):
-        class Foo(object):
+        class Foo:
             something = 'foo'
         original = Foo.something
         with patch.object(Foo, 'something'):
diff --git a/python/mock-1.0.0/tests/support.py b/python/mock-1.0.0/tests/support.py
index 1b10c3428f..a14fcc025d 100644
--- a/python/mock-1.0.0/tests/support.py
+++ b/python/mock-1.0.0/tests/support.py
@@ -24,18 +24,18 @@ def is_instance(obj, klass):
     return issubclass(type(obj), klass)
 
 
-class SomeClass(object):
+class SomeClass:
     class_attribute = None
 
     def wibble(self):
         pass
 
 
-class X(object):
+class X:
     pass
 
 try:
     next = next
 except NameError:
     def next(obj):
-        return obj.next()
+        return next(obj)
diff --git a/python/mock-1.0.0/tests/support_with.py b/python/mock-1.0.0/tests/support_with.py
index fa286122ce..dd22c1e456 100644
--- a/python/mock-1.0.0/tests/support_with.py
+++ b/python/mock-1.0.0/tests/support_with.py
@@ -1,5 +1,3 @@
-from __future__ import with_statement
-
 import sys
 
 __all__ = ['nested', 'catch_warnings', 'examine_warnings']
@@ -38,7 +36,7 @@ except ImportError:
 try:
     from warnings import catch_warnings
 except ImportError:
-    class catch_warnings(object):
+    class catch_warnings:
         def __init__(self, record=False, module=None):
             self._record = record
             self._module = sys.modules['warnings']
@@ -49,7 +47,7 @@ except ImportError:
             if self._record:
                 args.append("record=True")
             name = type(self).__name__
-            return "%s(%s)" % (name, ", ".join(args))
+            return "{}({})".format(name, ", ".join(args))
 
         def __enter__(self):
             if self._entered:
@@ -73,7 +71,7 @@ except ImportError:
             self._module.filters = self._filters
             self._module.showwarning = self._showwarning
 
-    class WarningMessage(object):
+    class WarningMessage:
         _WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
                             "line")
         def __init__(self, message, category, filename, lineno, file=None,
diff --git a/python/mock-1.0.0/tests/testcallable.py b/python/mock-1.0.0/tests/testcallable.py
index f7dcd5e1df..e78d15b2e2 100644
--- a/python/mock-1.0.0/tests/testcallable.py
+++ b/python/mock-1.0.0/tests/testcallable.py
@@ -4,7 +4,7 @@
 
 from tests.support import is_instance, unittest2, X, SomeClass
 
-from mock import (
+from unittest.mock import (
     Mock, MagicMock, NonCallableMagicMock,
     NonCallableMock, patch, create_autospec,
     CallableMixin
diff --git a/python/mock-1.0.0/tests/testhelpers.py b/python/mock-1.0.0/tests/testhelpers.py
index f41023c371..2f37612df1 100644
--- a/python/mock-1.0.0/tests/testhelpers.py
+++ b/python/mock-1.0.0/tests/testhelpers.py
@@ -4,14 +4,14 @@
 
 from tests.support import unittest2, inPy3k
 
-from mock import (
+from unittest.mock import (
     call, _Call, create_autospec, MagicMock,
     Mock, ANY, _CallList, patch, PropertyMock
 )
 
 from datetime import datetime
 
-class SomeClass(object):
+class SomeClass:
     def one(self, a, b):
         pass
     def two(self):
@@ -49,7 +49,7 @@ class AnyTest(unittest2.TestCase):
     def test_any_mock_calls_comparison_order(self):
         mock = Mock()
         d = datetime.utcnow()
-        class Foo(object):
+        class Foo:
             def __eq__(self, other):
                 return False
             def __ne__(self, other):
@@ -352,7 +352,7 @@ class SpecSignatureTest(unittest2.TestCase):
         mock = create_autospec(f, return_value='foo')
         self.assertEqual(mock(), 'foo')
 
-        class Foo(object):
+        class Foo:
             pass
 
         mock = create_autospec(Foo, return_value='foo')
@@ -367,7 +367,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_mocking_unbound_methods(self):
-        class Foo(object):
+        class Foo:
             def foo(self, foo):
                 pass
         p = patch.object(Foo, 'foo')
@@ -380,7 +380,7 @@ class SpecSignatureTest(unittest2.TestCase):
     @unittest2.expectedFailure
     def test_create_autospec_unbound_methods(self):
         # see issue 128
-        class Foo(object):
+        class Foo:
             def foo(self):
                 pass
 
@@ -395,7 +395,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_create_autospec_keyword_arguments(self):
-        class Foo(object):
+        class Foo:
             a = 3
         m = create_autospec(Foo, a='3')
         self.assertEqual(m.a, '3')
@@ -435,7 +435,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
         self.assertRaises(AttributeError, getattr, mock, 'foo')
 
-        class Foo(object):
+        class Foo:
             foo = []
 
         mock = create_autospec(Foo)
@@ -532,7 +532,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_descriptors(self):
-        class Foo(object):
+        class Foo:
             @classmethod
             def f(cls, a, b):
                 pass
@@ -578,7 +578,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_recursive(self):
-        class A(object):
+        class A:
             def a(self):
                 pass
             foo = 'foo bar baz'
@@ -601,10 +601,10 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_spec_inheritance_for_classes(self):
-        class Foo(object):
+        class Foo:
             def a(self):
                 pass
-            class Bar(object):
+            class Bar:
                 def f(self):
                     pass
 
@@ -637,7 +637,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_inherit(self):
-        class Foo(object):
+        class Foo:
             a = 3
 
         Foo.Foo = Foo
@@ -698,12 +698,12 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_skip_attributeerrors(self):
-        class Raiser(object):
+        class Raiser:
             def __get__(self, obj, type=None):
                 if obj is None:
                     raise AttributeError('Can only be accessed via an instance')
 
-        class RaiserClass(object):
+        class RaiserClass:
             raiser = Raiser()
 
             @staticmethod
@@ -721,7 +721,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_signature_class(self):
-        class Foo(object):
+        class Foo:
             def __init__(self, a, b=3):
                 pass
 
@@ -754,7 +754,7 @@ class SpecSignatureTest(unittest2.TestCase):
     def test_class_with_no_init(self):
         # this used to raise an exception
         # due to trying to get a signature from object.__init__
-        class Foo(object):
+        class Foo:
             pass
         create_autospec(Foo)
 
@@ -769,7 +769,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_signature_callable(self):
-        class Callable(object):
+        class Callable:
             def __init__(self):
                 pass
             def __call__(self, a):
@@ -796,7 +796,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_signature_noncallable(self):
-        class NonCallable(object):
+        class NonCallable:
             def __init__(self):
                 pass
 
@@ -813,7 +813,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_create_autospec_none(self):
-        class Foo(object):
+        class Foo:
             bar = None
 
         mock = create_autospec(Foo)
@@ -825,7 +825,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_autospec_functions_with_self_in_odd_place(self):
-        class Foo(object):
+        class Foo:
             def f(a, self):
                 pass
 
@@ -835,7 +835,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_autospec_property(self):
-        class Foo(object):
+        class Foo:
             @property
             def foo(self):
                 return 3
@@ -852,7 +852,7 @@ class SpecSignatureTest(unittest2.TestCase):
 
 
     def test_autospec_slots(self):
-        class Foo(object):
+        class Foo:
             __slots__ = ['a']
 
         foo = create_autospec(Foo)
diff --git a/python/mock-1.0.0/tests/testmagicmethods.py b/python/mock-1.0.0/tests/testmagicmethods.py
index ef0f16d826..faf24a51c1 100644
--- a/python/mock-1.0.0/tests/testmagicmethods.py
+++ b/python/mock-1.0.0/tests/testmagicmethods.py
@@ -5,15 +5,15 @@
 from tests.support import unittest2, inPy3k
 
 try:
-    unicode
+    str
 except NameError:
     # Python 3
-    unicode = str
+    str = str
     long = int
 
 import inspect
 import sys
-from mock import Mock, MagicMock, _magics
+from unittest.mock import Mock, MagicMock, _magics
 
 
 
@@ -83,10 +83,10 @@ class TestMockingMagicMethods(unittest2.TestCase):
     @unittest2.skipIf(inPy3k, "no unicode in Python 3")
     def test_unicode(self):
         mock = Mock()
-        self.assertEqual(unicode(mock), unicode(str(mock)))
+        self.assertEqual(str(mock), str(str(mock)))
 
-        mock.__unicode__ = lambda s: unicode('foo')
-        self.assertEqual(unicode(mock), unicode('foo'))
+        mock.__unicode__ = lambda s: str('foo')
+        self.assertEqual(str(mock), str('foo'))
 
 
     def test_dict_methods(self):
@@ -315,14 +315,14 @@ class TestMockingMagicMethods(unittest2.TestCase):
         self.assertEqual(int(mock), 1)
         self.assertEqual(complex(mock), 1j)
         self.assertEqual(float(mock), 1.0)
-        self.assertEqual(long(mock), long(1))
+        self.assertEqual(int(mock), int(1))
         self.assertNotIn(object(), mock)
         self.assertEqual(len(mock), 0)
         self.assertEqual(list(mock), [])
         self.assertEqual(hash(mock), object.__hash__(mock))
         self.assertEqual(str(mock), object.__str__(mock))
-        self.assertEqual(unicode(mock), object.__str__(mock))
-        self.assertIsInstance(unicode(mock), unicode)
+        self.assertEqual(str(mock), object.__str__(mock))
+        self.assertIsInstance(str(mock), str)
         self.assertTrue(bool(mock))
         if not inPy3k:
             self.assertEqual(oct(mock), '1')
@@ -346,7 +346,7 @@ class TestMockingMagicMethods(unittest2.TestCase):
 
 
     def test_magic_methods_and_spec(self):
-        class Iterable(object):
+        class Iterable:
             def __iter__(self):
                 pass
 
@@ -356,7 +356,7 @@ class TestMockingMagicMethods(unittest2.TestCase):
         mock.__iter__ = Mock(return_value=iter([]))
         self.assertEqual(list(mock), [])
 
-        class NonIterable(object):
+        class NonIterable:
             pass
         mock = Mock(spec=NonIterable)
         self.assertRaises(AttributeError, lambda: mock.__iter__)
@@ -371,7 +371,7 @@ class TestMockingMagicMethods(unittest2.TestCase):
 
 
     def test_magic_methods_and_spec_set(self):
-        class Iterable(object):
+        class Iterable:
             def __iter__(self):
                 pass
 
@@ -381,7 +381,7 @@ class TestMockingMagicMethods(unittest2.TestCase):
         mock.__iter__ = Mock(return_value=iter([]))
         self.assertEqual(list(mock), [])
 
-        class NonIterable(object):
+        class NonIterable:
             pass
         mock = Mock(spec_set=NonIterable)
         self.assertRaises(AttributeError, lambda: mock.__iter__)
@@ -399,7 +399,7 @@ class TestMockingMagicMethods(unittest2.TestCase):
         mock = MagicMock()
         def set_setattr():
             mock.__setattr__ = lambda self, name: None
-        self.assertRaisesRegexp(AttributeError,
+        self.assertRaisesRegex(AttributeError,
             "Attempting to set unsupported magic method '__setattr__'.",
             set_setattr
         )
diff --git a/python/mock-1.0.0/tests/testmock.py b/python/mock-1.0.0/tests/testmock.py
index f3ceea9955..3f6cb2da00 100644
--- a/python/mock-1.0.0/tests/testmock.py
+++ b/python/mock-1.0.0/tests/testmock.py
@@ -10,8 +10,8 @@ import copy
 import pickle
 import sys
 
-import mock
-from mock import (
+from unittest import mock
+from unittest.mock import (
     call, DEFAULT, patch, sentinel,
     MagicMock, Mock, NonCallableMock,
     NonCallableMagicMock, _CallList,
@@ -20,12 +20,12 @@ from mock import (
 
 
 try:
-    unicode
+    str
 except NameError:
-    unicode = str
+    str = str
 
 
-class Iter(object):
+class Iter:
     def __init__(self):
         self.thing = iter(['this', 'is', 'an', 'iter'])
 
@@ -42,7 +42,7 @@ class Subclass(MagicMock):
     pass
 
 
-class Thing(object):
+class Thing:
     attribute = 6
     foo = 'bar'
 
@@ -87,7 +87,7 @@ class MockTest(unittest2.TestCase):
 
     def test_unicode_not_broken(self):
         # This used to raise an exception with Python 2.5 and Mock 0.4
-        unicode(Mock())
+        str(Mock())
 
 
     def test_return_value_in_constructor(self):
@@ -113,7 +113,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_repr_with_spec(self):
-        class X(object):
+        class X:
             pass
 
         mock = Mock(spec=X)
@@ -396,7 +396,7 @@ class MockTest(unittest2.TestCase):
 
                 # this should be allowed
                 mock.something
-                self.assertRaisesRegexp(
+                self.assertRaisesRegex(
                     AttributeError,
                     "Mock object has no attribute 'something_else'",
                     getattr, mock, 'something_else'
@@ -404,7 +404,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_from_spec(self):
-        class Something(object):
+        class Something:
             x = 3
             __something__ = None
             def y(self):
@@ -415,12 +415,12 @@ class MockTest(unittest2.TestCase):
             mock.x
             mock.y
             mock.__something__
-            self.assertRaisesRegexp(
+            self.assertRaisesRegex(
                 AttributeError,
                 "Mock object has no attribute 'z'",
                 getattr, mock, 'z'
             )
-            self.assertRaisesRegexp(
+            self.assertRaisesRegex(
                 AttributeError,
                 "Mock object has no attribute '__foobar__'",
                 getattr, mock, '__foobar__'
@@ -453,7 +453,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_wraps_attributes(self):
-        class Real(object):
+        class Real:
             attribute = Mock()
 
         real = Real()
@@ -486,7 +486,7 @@ class MockTest(unittest2.TestCase):
 
     def test_assert_called_with_message(self):
         mock = Mock()
-        self.assertRaisesRegexp(AssertionError, 'Not called',
+        self.assertRaisesRegex(AssertionError, 'Not called',
                                 mock.assert_called_with)
 
 
@@ -509,7 +509,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_spec_class(self):
-        class X(object):
+        class X:
             pass
 
         mock = Mock(spec=X)
@@ -529,7 +529,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_setting_attribute_with_spec_set(self):
-        class X(object):
+        class X:
             y = 3
 
         mock = Mock(spec=X)
@@ -547,7 +547,7 @@ class MockTest(unittest2.TestCase):
         current = sys.getrecursionlimit()
         self.addCleanup(sys.setrecursionlimit, current)
 
-        # can't use sys.maxint as this doesn't exist in Python 3
+        # can't use sys.maxsize as this doesn't exist in Python 3
         sys.setrecursionlimit(int(10e8))
         # this segfaults without the fix in place
         copy.copy(Mock())
@@ -626,7 +626,7 @@ class MockTest(unittest2.TestCase):
     def test_dir(self):
         mock = Mock()
         attrs = set(dir(mock))
-        type_attrs = set([m for m in dir(Mock) if not m.startswith('_')])
+        type_attrs = {m for m in dir(Mock) if not m.startswith('_')}
 
         # all public attributes from the type are included
         self.assertEqual(set(), type_attrs - attrs)
@@ -705,7 +705,7 @@ class MockTest(unittest2.TestCase):
             instance = sys.exc_info()[1]
             self.assertIsInstance(instance, exception)
         else:
-            self.fail('Exception %r not raised' % (exception,))
+            self.fail('Exception {!r} not raised'.format(exception))
 
         msg = str(instance)
         self.assertEqual(msg, message)
@@ -926,7 +926,7 @@ class MockTest(unittest2.TestCase):
         self.assertEqual([mock(), mock(), mock()], ['g', 'h', 'i'])
         self.assertRaises(StopIteration, mock)
 
-        class Foo(object):
+        class Foo:
             pass
         mock = MagicMock(side_effect=Foo)
         self.assertIsInstance(mock(), Foo)
@@ -1099,11 +1099,11 @@ class MockTest(unittest2.TestCase):
 
 
     def test_mock_add_spec(self):
-        class _One(object):
+        class _One:
             one = 1
-        class _Two(object):
+        class _Two:
             two = 2
-        class Anything(object):
+        class Anything:
             one = two = three = 'four'
 
         klasses = [
@@ -1202,7 +1202,7 @@ class MockTest(unittest2.TestCase):
 
 
     def test_manager_mock(self):
-        class Foo(object):
+        class Foo:
             one = 'one'
             two = 'two'
         manager = Mock()
diff --git a/python/mock-1.0.0/tests/testpatch.py b/python/mock-1.0.0/tests/testpatch.py
index 1ebe671065..37b395374c 100644
--- a/python/mock-1.0.0/tests/testpatch.py
+++ b/python/mock-1.0.0/tests/testpatch.py
@@ -8,7 +8,7 @@ import sys
 from tests import support
 from tests.support import unittest2, inPy3k, SomeClass, is_instance, callable
 
-from mock import (
+from unittest.mock import (
     NonCallableMock, CallableMixin, patch, sentinel,
     MagicMock, Mock, NonCallableMagicMock, patch, _patch,
     DEFAULT, call, _get_target
@@ -17,14 +17,14 @@ from mock import (
 builtin_string = '__builtin__'
 if inPy3k:
     builtin_string = 'builtins'
-    unicode = str
+    str = str
 
 PTModule = sys.modules[__name__]
 MODNAME = '%s.PTModule' % __name__
 
 
 def _get_proxy(obj, get_only=True):
-    class Proxy(object):
+    class Proxy:
         def __getattr__(self, name):
             return getattr(obj, name)
     if not get_only:
@@ -42,7 +42,7 @@ something  = sentinel.Something
 something_else  = sentinel.SomethingElse
 
 
-class Foo(object):
+class Foo:
     def __init__(self, a):
         pass
     def f(self, a):
@@ -51,7 +51,7 @@ class Foo(object):
         pass
     foo = 'bar'
 
-    class Bar(object):
+    class Bar:
         def a(self):
             pass
 
@@ -62,7 +62,7 @@ def function(a, b=Foo):
     pass
 
 
-class Container(object):
+class Container:
     def __init__(self):
         self.values = {}
 
@@ -93,7 +93,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_single_patchobject(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
 
         @patch.object(Something, 'attribute', sentinel.Patched)
@@ -106,7 +106,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patchobject_with_none(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
 
         @patch.object(Something, 'attribute', None)
@@ -119,7 +119,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_multiple_patchobject(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
             next_attribute = sentinel.Original2
 
@@ -188,7 +188,7 @@ class PatchTest(unittest2.TestCase):
         mock.return_value = sentinel.Handle
         @patch('%s.open' % builtin_string, mock)
         def test():
-            self.assertEqual(open('filename', 'r'), sentinel.Handle,
+            self.assertEqual(open('filename'), sentinel.Handle,
                              "open not patched")
         test()
         test()
@@ -209,7 +209,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patchobject_with_default_mock(self):
-        class Test(object):
+        class Test:
             something = sentinel.Original
             something2 = sentinel.Original2
 
@@ -391,7 +391,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_with_static_methods(self):
-        class Foo(object):
+        class Foo:
             @staticmethod
             def woot():
                 return sentinel.Static
@@ -415,7 +415,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_slots(self):
-        class Foo(object):
+        class Foo:
             __slots__ = ('Foo',)
 
         foo = Foo()
@@ -430,10 +430,10 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patchobject_class_decorator(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
 
-        class Foo(object):
+        class Foo:
             def test_method(other_self):
                 self.assertEqual(Something.attribute, sentinel.Patched,
                                  "unpatched")
@@ -452,10 +452,10 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_class_decorator(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
 
-        class Foo(object):
+        class Foo:
             def test_method(other_self, mock_something):
                 self.assertEqual(PTModule.something, mock_something,
                                  "unpatched")
@@ -475,7 +475,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patchobject_twice(self):
-        class Something(object):
+        class Something:
             attribute = sentinel.Original
             next_attribute = sentinel.Original2
 
@@ -648,10 +648,10 @@ class PatchTest(unittest2.TestCase):
     def test_patch_descriptor(self):
         # would be some effort to fix this - we could special case the
         # builtin descriptors: classmethod, property, staticmethod
-        class Nothing(object):
+        class Nothing:
             foo = None
 
-        class Something(object):
+        class Something:
             foo = {}
 
             @patch.object(Nothing, 'foo', 2)
@@ -773,7 +773,7 @@ class PatchTest(unittest2.TestCase):
         d = {'spam': 'eggs'}
         original = d.copy()
 
-        class Test(object):
+        class Test:
             def test_first(self):
                 this.assertEqual(d, {'foo': 'bar'})
             def test_second(self):
@@ -800,7 +800,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_get_only_proxy(self):
-        class Something(object):
+        class Something:
             foo = 'foo'
         class SomethingElse:
             foo = 'foo'
@@ -818,7 +818,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_get_set_delete_proxy(self):
-        class Something(object):
+        class Something:
             foo = 'foo'
         class SomethingElse:
             foo = 'foo'
@@ -877,7 +877,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_autospec(self):
-        class Boo(object):
+        class Boo:
             def __init__(self, a):
                 pass
             def f(self, a):
@@ -886,7 +886,7 @@ class PatchTest(unittest2.TestCase):
                 pass
             foo = 'bar'
 
-            class Bar(object):
+            class Bar:
                 def a(self):
                     pass
 
@@ -1059,7 +1059,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_new_callable_keyword_arguments(self):
-        class Bar(object):
+        class Bar:
             kwargs = None
             def __init__(self, **kwargs):
                 Bar.kwargs = kwargs
@@ -1074,7 +1074,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_new_callable_spec(self):
-        class Bar(object):
+        class Bar:
             kwargs = None
             def __init__(self, **kwargs):
                 Bar.kwargs = kwargs
@@ -1149,7 +1149,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_new_callable_inherit_non_mock(self):
-        class NotAMock(object):
+        class NotAMock:
             def __init__(self, spec):
                 self.spec = spec
 
@@ -1167,7 +1167,7 @@ class PatchTest(unittest2.TestCase):
     def test_new_callable_class_decorating(self):
         test = self
         original = Foo
-        class SomeTest(object):
+        class SomeTest:
 
             def _test(self, mock_foo):
                 test.assertIsNot(Foo, original)
@@ -1316,7 +1316,7 @@ class PatchTest(unittest2.TestCase):
         try:
             f = result['f']
             foo = result['foo']
-            self.assertEqual(set(result), set(['f', 'foo']))
+            self.assertEqual(set(result), {'f', 'foo'})
 
             self.assertIs(Foo, original_foo)
             self.assertIs(Foo.f, f)
@@ -1336,7 +1336,7 @@ class PatchTest(unittest2.TestCase):
         original_f = Foo.f
         original_g = Foo.g
 
-        class SomeTest(object):
+        class SomeTest:
 
             def _test(self, f, foo):
                 test.assertIs(Foo, original_foo)
@@ -1394,7 +1394,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_multiple_new_callable(self):
-        class Thing(object):
+        class Thing:
             pass
 
         patcher = patch.multiple(
@@ -1528,7 +1528,7 @@ class PatchTest(unittest2.TestCase):
 
 
     def test_patch_multiple_string_subclasses(self):
-        for base in (str, unicode):
+        for base in (str, str):
             Foo = type('Foo', (base,), {'fish': 'tasty'})
             foo = Foo()
             @patch.multiple(foo, fish='nearly gone')
@@ -1541,7 +1541,7 @@ class PatchTest(unittest2.TestCase):
 
     @patch('mock.patch.TEST_PREFIX', 'foo')
     def test_patch_test_prefix(self):
-        class Foo(object):
+        class Foo:
             thing = 'original'
 
             def foo_one(self):
@@ -1564,7 +1564,7 @@ class PatchTest(unittest2.TestCase):
 
     @patch('mock.patch.TEST_PREFIX', 'bar')
     def test_patch_dict_test_prefix(self):
-        class Foo(object):
+        class Foo:
             def bar_one(self):
                 return dict(the_dict)
             def bar_two(self):
diff --git a/python/mock-1.0.0/tests/testsentinel.py b/python/mock-1.0.0/tests/testsentinel.py
index 981171a450..cd9200a3bc 100644
--- a/python/mock-1.0.0/tests/testsentinel.py
+++ b/python/mock-1.0.0/tests/testsentinel.py
@@ -4,7 +4,7 @@
 
 from tests.support import unittest2
 
-from mock import sentinel, DEFAULT
+from unittest.mock import sentinel, DEFAULT
 
 
 class SentinelTest(unittest2.TestCase):
diff --git a/python/mozbuild/dumbmake/dumbmake.py b/python/mozbuild/dumbmake/dumbmake.py
index 5457c8b0a0..7ba2725a14 100644
--- a/python/mozbuild/dumbmake/dumbmake.py
+++ b/python/mozbuild/dumbmake/dumbmake.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 from collections import OrderedDict
 from itertools import groupby
@@ -36,7 +35,7 @@ def dependency_map(lines):
     deps = {}
 
     for i, (indent, target) in enumerate(pairs):
-        if not deps.has_key(target):
+        if target not in deps:
             deps[target] = []
 
         for j in range(i+1, len(pairs)):
@@ -68,7 +67,7 @@ def all_dependencies(*targets, **kwargs):
                     del all_targets[dependency]
                 all_targets[dependency] = True
 
-    return all_targets.keys()
+    return list(all_targets.keys())
 
 def get_components(path):
     """Take a path and return all the components of the path."""
@@ -114,7 +113,7 @@ def add_extra_dependencies(target_pairs, dependency_map):
                 make_dirs[make_dir] = True
 
     all_components = []
-    for make_dir in make_dirs.iterkeys():
+    for make_dir in make_dirs.keys():
         all_components.extend(get_components(make_dir))
 
     for i in all_dependencies(*all_components, dependency_map=dependency_map):
diff --git a/python/mozbuild/dumbmake/test/test_dumbmake.py b/python/mozbuild/dumbmake/test/test_dumbmake.py
index 1172117aaf..d157f26804 100644
--- a/python/mozbuild/dumbmake/test/test_dumbmake.py
+++ b/python/mozbuild/dumbmake/test/test_dumbmake.py
@@ -1,7 +1,6 @@
 # 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 unicode_literals
 
 import unittest
 
diff --git a/python/mozbuild/mozbuild/action/buildlist.py b/python/mozbuild/mozbuild/action/buildlist.py
index 9d601d69a9..fd129eab77 100644
--- a/python/mozbuild/mozbuild/action/buildlist.py
+++ b/python/mozbuild/mozbuild/action/buildlist.py
@@ -7,7 +7,6 @@ if the entry does not already exist.
 
 Usage: buildlist.py <filename> <entry> [<entry> ...]
 '''
-from __future__ import absolute_import, print_function
 
 import sys
 import os
@@ -26,14 +25,14 @@ def addEntriesToListFile(listFile, entries):
   try:
     if os.path.exists(listFile):
       f = open(listFile)
-      existing = set(x.strip() for x in f.readlines())
+      existing = {x.strip() for x in f.readlines()}
       f.close()
     else:
       existing = set()
     for e in entries:
       if e not in existing:
         existing.add(e)
-    with open(listFile, 'wb') as f:
+    with open(listFile, 'w') as f:
       f.write("\n".join(sorted(existing))+"\n")
   finally:
     lock = None
diff --git a/python/mozbuild/mozbuild/action/cl.py b/python/mozbuild/mozbuild/action/cl.py
index 1840d7d857..f9f9ebcbae 100644
--- a/python/mozbuild/mozbuild/action/cl.py
+++ b/python/mozbuild/mozbuild/action/cl.py
@@ -2,7 +2,6 @@
 # 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 ctypes
 import os
@@ -55,7 +54,7 @@ def InvokeClWithDependencyGeneration(cmdline):
             break
 
     if target is None:
-        print >>sys.stderr, "No target set"
+        print("No target set", file=sys.stderr)
         return 1
 
     # Assume the source file is the last argument
diff --git a/python/mozbuild/mozbuild/action/dump_env.py b/python/mozbuild/mozbuild/action/dump_env.py
index 83e420d682..3376b6207e 100644
--- a/python/mozbuild/mozbuild/action/dump_env.py
+++ b/python/mozbuild/mozbuild/action/dump_env.py
@@ -5,6 +5,7 @@
 # We invoke a Python program to dump our environment in order to get
 # native paths printed on Windows so that these paths can be incorporated
 # into Python configure's environment.
+from __future__ import print_function
 import os
 import sys
 
@@ -13,4 +14,4 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 from shellutil import quote
 
 for key, value in os.environ.items():
-    print('%s=%s' % (key, quote(value)))
+    print(('{}={}'.format(key, quote(value))))
diff --git a/python/mozbuild/mozbuild/action/file_generate.py b/python/mozbuild/mozbuild/action/file_generate.py
index 3bdbc264bd..5b505cd64b 100644
--- a/python/mozbuild/mozbuild/action/file_generate.py
+++ b/python/mozbuild/mozbuild/action/file_generate.py
@@ -6,10 +6,9 @@
 # the arguments that can be used to generate the output file, call the
 # script's |main| method with appropriate arguments.
 
-from __future__ import absolute_import, print_function
 
 import argparse
-import imp
+import importlib.util
 import os
 import sys
 import traceback
@@ -47,13 +46,26 @@ def main(argv):
     # then importing modules from the script's directory would come for free.
     # Since we're invoking the script in a roundabout way, we provide this
     # bit of convenience.
-    sys.path.append(os.path.dirname(script))
-    with open(script, 'r') as fh:
-        module = imp.load_module('script', fh, script,
-                                 ('.py', 'r', imp.PY_SOURCE))
+    script_dir = os.path.dirname(script)
+    sys.path.append(script_dir)
+    # If the script lives inside a package, load it with its qualified name
+    # so that relative imports (from . import ...) resolve correctly.
+    if os.path.isfile(os.path.join(script_dir, '__init__.py')):
+        parent_dir = os.path.dirname(script_dir)
+        if parent_dir not in sys.path:
+            sys.path.insert(0, parent_dir)
+        pkg_name = os.path.basename(script_dir)
+        mod_name = '{}.{}'.format(pkg_name,
+                                  os.path.splitext(os.path.basename(script))[0])
+    else:
+        mod_name = 'script'
+    _spec = importlib.util.spec_from_file_location(mod_name, script)
+    module = importlib.util.module_from_spec(_spec)
+    sys.modules[mod_name] = module
+    _spec.loader.exec_module(module)
     method = args.method_name
     if not hasattr(module, method):
-        print('Error: script "{0}" is missing a {1} method'.format(script, method),
+        print('Error: script "{}" is missing a {} method'.format(script, method),
               file=sys.stderr)
         return 1
 
@@ -95,11 +107,11 @@ def main(argv):
         try:
             os.utime(args.output_file, None)
         except:
-            print('Error processing file "{0}"'.format(args.output_file),
+            print('Error processing file "{}"'.format(args.output_file),
                   file=sys.stderr)
             traceback.print_exc()
-    except IOError as e:
-        print('Error opening file "{0}"'.format(e.filename), file=sys.stderr)
+    except OSError as e:
+        print('Error opening file "{}"'.format(e.filename), file=sys.stderr)
         traceback.print_exc()
         return 1
     return ret
diff --git a/python/mozbuild/mozbuild/action/generate_browsersearch.py b/python/mozbuild/mozbuild/action/generate_browsersearch.py
index 231abe9be3..9fe90159b2 100644
--- a/python/mozbuild/mozbuild/action/generate_browsersearch.py
+++ b/python/mozbuild/mozbuild/action/generate_browsersearch.py
@@ -30,11 +30,6 @@ to browsersearch.json in the locale-specific raw resource directory
 e.g. raw/browsersearch.json, raw-pt-rBR/browsersearch.json.
 '''
 
-from __future__ import (
-    absolute_import,
-    print_function,
-    unicode_literals,
-)
 
 import argparse
 import codecs
@@ -58,7 +53,7 @@ def merge_properties(filename, srcdirs):
         path = mozpath.join(srcdir, filename)
         try:
             properties.update(path)
-        except IOError:
+        except OSError:
             # Ignore non-existing files
             continue
     return properties
diff --git a/python/mozbuild/mozbuild/action/generate_symbols_file.py b/python/mozbuild/mozbuild/action/generate_symbols_file.py
index 3eebf324cc..af1bb6fb3c 100644
--- a/python/mozbuild/mozbuild/action/generate_symbols_file.py
+++ b/python/mozbuild/mozbuild/action/generate_symbols_file.py
@@ -2,12 +2,11 @@
 # 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, print_function, unicode_literals
 
 import argparse
 import buildconfig
 import os
-from StringIO import StringIO
+from io import StringIO
 from mozbuild.preprocessor import Preprocessor
 from mozbuild.util import DefinesAction
 
diff --git a/python/mozbuild/mozbuild/action/jar_maker.py b/python/mozbuild/mozbuild/action/jar_maker.py
index 3e3c3c83ef..6fc45cdf66 100644
--- a/python/mozbuild/mozbuild/action/jar_maker.py
+++ b/python/mozbuild/mozbuild/action/jar_maker.py
@@ -2,7 +2,6 @@
 # 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 sys
 
diff --git a/python/mozbuild/mozbuild/action/make_dmg.py b/python/mozbuild/mozbuild/action/make_dmg.py
index 8d77bf3744..0612bc9d3b 100644
--- a/python/mozbuild/mozbuild/action/make_dmg.py
+++ b/python/mozbuild/mozbuild/action/make_dmg.py
@@ -2,7 +2,6 @@
 # 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 print_function
 
 from mozbuild.base import MozbuildObject
 from mozpack import dmg
diff --git a/python/mozbuild/mozbuild/action/output_searchplugins_list.py b/python/mozbuild/mozbuild/action/output_searchplugins_list.py
index c20e2c7328..9effb97665 100644
--- a/python/mozbuild/mozbuild/action/output_searchplugins_list.py
+++ b/python/mozbuild/mozbuild/action/output_searchplugins_list.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import sys
 import json
 
@@ -18,4 +19,4 @@ if locale in searchinfo["locales"]:
 else:
   engines = searchinfo["default"]["visibleDefaultEngines"]
 
-print '\n'.join(engines)
+print(('\n'.join(engines)))
diff --git a/python/mozbuild/mozbuild/action/preprocessor.py b/python/mozbuild/mozbuild/action/preprocessor.py
index e5a4d576ba..24f3ffe60f 100644
--- a/python/mozbuild/mozbuild/action/preprocessor.py
+++ b/python/mozbuild/mozbuild/action/preprocessor.py
@@ -2,7 +2,6 @@
 # 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 sys
 
diff --git a/python/mozbuild/mozbuild/action/process_define_files.py b/python/mozbuild/mozbuild/action/process_define_files.py
index f6d0c1695a..fb7d32a292 100644
--- a/python/mozbuild/mozbuild/action/process_define_files.py
+++ b/python/mozbuild/mozbuild/action/process_define_files.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import argparse
 import os
@@ -39,8 +38,8 @@ def process_define_file(output, input):
         config = ConfigEnvironment.from_config_status(
             mozpath.join(topobjdir, 'js', 'src', 'config.status'))
 
-    with open(path, 'rU') as input:
-        r = re.compile('^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>\S+))?)?', re.U)
+    with open(path) as input:
+        r = re.compile(r'^\s*#\s*(?P<cmd>[a-z]+)(?:\s+(?P<name>\S+)(?:\s+(?P<value>\S+))?)?', re.U)
         for l in input:
             m = r.match(l)
             if m:
@@ -54,8 +53,8 @@ def process_define_file(output, input):
                                 '`#define ALLDEFINES` is not allowed in a '
                                 'CONFIGURE_DEFINE_FILE')
                         defines = '\n'.join(sorted(
-                            '#define %s %s' % (name, val)
-                            for name, val in config.defines.iteritems()
+                            '#define {} {}'.format(name, val)
+                            for name, val in config.defines.items()
                             if name not in config.non_global_defines))
                         l = l[:m.start('cmd') - 1] \
                             + defines + l[m.end('name'):]
diff --git a/python/mozbuild/mozbuild/action/process_install_manifest.py b/python/mozbuild/mozbuild/action/process_install_manifest.py
index a97a72cc6e..177b724772 100644
--- a/python/mozbuild/mozbuild/action/process_install_manifest.py
+++ b/python/mozbuild/mozbuild/action/process_install_manifest.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 import argparse
 import os
 import sys
@@ -102,13 +102,13 @@ def main(argv):
 
     elapsed = time.time() - start
 
-    print(COMPLETE.format(
+    print((COMPLETE.format(
         elapsed=elapsed,
         dest=args.destdir,
         existing=result.existing_files_count,
         updated=result.updated_files_count,
         rm_files=result.removed_files_count,
-        rm_dirs=result.removed_directories_count))
+        rm_dirs=result.removed_directories_count)))
 
 if __name__ == '__main__':
     main(sys.argv[1:])
diff --git a/python/mozbuild/mozbuild/action/test_archive.py b/python/mozbuild/mozbuild/action/test_archive.py
index 8ec4dd2a90..1ec7d12743 100644
--- a/python/mozbuild/mozbuild/action/test_archive.py
+++ b/python/mozbuild/mozbuild/action/test_archive.py
@@ -8,8 +8,8 @@
 # It is defined inline because this was easiest to make test archive
 # generation faster.
 
-from __future__ import absolute_import, print_function, unicode_literals
 
+from __future__ import print_function
 import argparse
 import itertools
 import os
@@ -200,10 +200,10 @@ ARCHIVE_FILES = {
             'source': buildconfig.topobjdir,
             'base': 'dist/bin',
             'patterns': [
-                '%s%s' % (f, buildconfig.substs['BIN_SUFFIX'])
+                '{}{}'.format(f, buildconfig.substs['BIN_SUFFIX'])
                 for f in TEST_HARNESS_BINS
             ] + [
-                '%s%s%s' % (buildconfig.substs['DLL_PREFIX'], f, buildconfig.substs['DLL_SUFFIX'])
+                '{}{}{}'.format(buildconfig.substs['DLL_PREFIX'], f, buildconfig.substs['DLL_SUFFIX'])
                 for f in TEST_HARNESS_DLLS
             ],
             'dest': 'bin',
@@ -212,7 +212,7 @@ ARCHIVE_FILES = {
             'source': buildconfig.topobjdir,
             'base': 'dist/plugins',
             'patterns': [
-                '%s%s%s' % (buildconfig.substs['DLL_PREFIX'], f, buildconfig.substs['DLL_SUFFIX'])
+                '{}{}{}'.format(buildconfig.substs['DLL_PREFIX'], f, buildconfig.substs['DLL_SUFFIX'])
                 for f in TEST_PLUGIN_DLLS
             ],
             'dest': 'bin/plugins',
@@ -499,7 +499,7 @@ def find_manifest_dirs(topsrcdir, manifests):
         if p.endswith('.ini'):
             test_manifest = TestManifest()
             test_manifest.read(p)
-            dirs |= set([os.path.dirname(m) for m in test_manifest.manifests()])
+            dirs |= {os.path.dirname(m) for m in test_manifest.manifests()}
 
         elif p.endswith('.list'):
             m = ReftestManifest()
@@ -557,8 +557,8 @@ def main(argv):
     duration = time.time() - t_start
     zip_size = os.path.getsize(args.outputfile)
     basename = os.path.basename(args.outputfile)
-    print('Wrote %d files in %d bytes to %s in %.2fs' % (
-          file_count, zip_size, basename, duration))
+    print(('Wrote %d files in %d bytes to %s in %.2fs' % (
+          file_count, zip_size, basename, duration)))
 
 
 if __name__ == '__main__':
diff --git a/python/mozbuild/mozbuild/action/webidl.py b/python/mozbuild/mozbuild/action/webidl.py
index d595c728ec..a8cd3aea96 100644
--- a/python/mozbuild/mozbuild/action/webidl.py
+++ b/python/mozbuild/mozbuild/action/webidl.py
@@ -2,7 +2,6 @@
 # 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 sys
 
diff --git a/python/mozbuild/mozbuild/action/xpccheck.py b/python/mozbuild/mozbuild/action/xpccheck.py
index c3170a8da8..eec9664a09 100644
--- a/python/mozbuild/mozbuild/action/xpccheck.py
+++ b/python/mozbuild/mozbuild/action/xpccheck.py
@@ -8,7 +8,6 @@ corresponding .ini file.
 Usage: xpccheck.py <directory> [<directory> ...]
 '''
 
-from __future__ import absolute_import
 
 import sys
 import os
@@ -40,7 +39,7 @@ def verifyDirectory(initests, directory):
         break
    
     if not found:
-      print >>sys.stderr, "TEST-UNEXPECTED-FAIL | xpccheck | test %s is missing from test manifest %s!" % (name, os.path.join(directory, 'xpcshell.ini'))
+      print("TEST-UNEXPECTED-FAIL | xpccheck | test {} is missing from test manifest {}!".format(name, os.path.join(directory, 'xpcshell.ini')), file=sys.stderr)
       sys.exit(1)
 
 def verifyIniFile(initests, directory):
@@ -60,12 +59,12 @@ def verifyIniFile(initests, directory):
         break
 
     if not found:
-      print >>sys.stderr, "TEST-UNEXPECTED-FAIL | xpccheck | found %s in xpcshell.ini and not in directory '%s'" % (name, directory)
+      print("TEST-UNEXPECTED-FAIL | xpccheck | found {} in xpcshell.ini and not in directory '{}'".format(name, directory), file=sys.stderr)
       sys.exit(1)
 
 def main(argv):
   if len(argv) < 2:
-    print >>sys.stderr, "Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]"
+    print("Usage: xpccheck.py <topsrcdir> <directory> [<directory> ...]", file=sys.stderr)
     sys.exit(1)
 
   topsrcdir = argv[0]
diff --git a/python/mozbuild/mozbuild/action/xpidl-process.py b/python/mozbuild/mozbuild/action/xpidl-process.py
index 07ea3cf967..68afa353ac 100755
--- a/python/mozbuild/mozbuild/action/xpidl-process.py
+++ b/python/mozbuild/mozbuild/action/xpidl-process.py
@@ -7,7 +7,6 @@
 # input IDL file(s). It's purpose is to directly support the build
 # system. The API will change to meet the needs of the build system.
 
-from __future__ import absolute_import
 
 import argparse
 import os
@@ -58,7 +57,7 @@ def process(input_dir, inc_paths, cache_dir, header_dir, xpt_dir, deps_dir, modu
 
     # TODO use FileAvoidWrite once it supports binary mode.
     xpt_path = os.path.join(xpt_dir, '%s.xpt' % module)
-    xpt_link(xpts.values()).write(xpt_path)
+    xpt_link(list(xpts.values())).write(xpt_path)
 
     rule.add_targets([xpt_path])
     if deps_dir:
diff --git a/python/mozbuild/mozbuild/action/zip.py b/python/mozbuild/mozbuild/action/zip.py
index 143d7766e6..5e3a63734d 100644
--- a/python/mozbuild/mozbuild/action/zip.py
+++ b/python/mozbuild/mozbuild/action/zip.py
@@ -5,7 +5,6 @@
 # This script creates a zip file, but will also strip any binaries
 # it finds before adding them to the zip.
 
-from __future__ import absolute_import
 
 from mozpack.files import FileFinder
 from mozpack.copier import Jarrer
diff --git a/python/mozbuild/mozbuild/artifacts.py b/python/mozbuild/mozbuild/artifacts.py
index 02538938fb..c72e97fe39 100644
--- a/python/mozbuild/mozbuild/artifacts.py
+++ b/python/mozbuild/mozbuild/artifacts.py
@@ -40,7 +40,6 @@ consumers will need to arrange this themselves.
 '''
 
 
-from __future__ import absolute_import, print_function, unicode_literals
 
 import collections
 import functools
@@ -57,7 +56,7 @@ import stat
 import subprocess
 import tarfile
 import tempfile
-import urlparse
+import urllib.parse
 import zipfile
 
 import pylru
@@ -84,7 +83,6 @@ from mozregression.download_manager import (
 from mozregression.persist_limit import (
     PersistLimit,
 )
-
 NUM_PUSHHEADS_TO_QUERY_PER_PARENT = 50  # Number of candidate pushheads to cache per parent changeset.
 
 # Number of parent changesets to consider as possible pushheads.
@@ -112,7 +110,7 @@ CANDIDATE_TREES = (
     'releases/mozilla-aurora'
 )
 
-class ArtifactJob(object):
+class ArtifactJob:
     # These are a subset of TEST_HARNESS_BINS in testing/mochitest/Makefile.in.
     # Each item is a pair of (pattern, (src_prefix, dest_prefix), where src_prefix
     # is the prefix of the pattern relevant to its location in the archive, and
@@ -183,7 +181,7 @@ class ArtifactJob(object):
 
         with JarWriter(file=processed_filename, optimize=False, compress_level=5) as writer:
             reader = JarReader(filename)
-            for filename, entry in reader.entries.iteritems():
+            for filename, entry in reader.entries.items():
                 for pattern, (src_prefix, dest_prefix) in self.test_artifact_patterns:
                     if not mozpath.match(filename, pattern):
                         continue
@@ -378,7 +376,7 @@ class MacArtifactJob(ArtifactJob):
         finally:
             try:
                 shutil.rmtree(tempdir)
-            except (OSError, IOError):
+            except OSError:
                 self.log(logging.WARN, 'artifact',
                     {'tempdir': tempdir},
                     'Unable to delete {tempdir}')
@@ -442,26 +440,26 @@ JOB_DETAILS = {
                                                   None)),
     'android-x86-opt': (AndroidArtifactJob, ('public/build/target.apk',
                                          None)),
-    'linux-opt': (LinuxArtifactJob, ('public/build/firefox-(.*)\.linux-i686\.tar\.bz2',
-                                     'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'linux-debug': (LinuxArtifactJob, ('public/build/firefox-(.*)\.linux-i686\.tar\.bz2',
-                                 'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'linux64-opt': (LinuxArtifactJob, ('public/build/firefox-(.*)\.linux-x86_64\.tar\.bz2',
-                                       'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'linux64-debug': (LinuxArtifactJob, ('public/build/target\.tar\.bz2',
-                                         'public/build/target\.common\.tests\.zip')),
-    'macosx64-opt': (MacArtifactJob, ('public/build/firefox-(.*)\.mac\.dmg',
-                                      'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'macosx64-debug': (MacArtifactJob, ('public/build/firefox-(.*)\.mac64\.dmg',
-                                  'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'win32-opt': (WinArtifactJob, ('public/build/firefox-(.*)\.win32.zip',
-                                   'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'win32-debug': (WinArtifactJob, ('public/build/firefox-(.*)\.win32.zip',
-                               'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'win64-opt': (WinArtifactJob, ('public/build/firefox-(.*)\.win64.zip',
-                                   'public/build/firefox-(.*)\.common\.tests\.zip')),
-    'win64-debug': (WinArtifactJob, ('public/build/firefox-(.*)\.win64.zip',
-                               'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'linux-opt': (LinuxArtifactJob, (r'public/build/firefox-(.*)\.linux-i686\.tar\.bz2',
+                                     r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'linux-debug': (LinuxArtifactJob, (r'public/build/firefox-(.*)\.linux-i686\.tar\.bz2',
+                                 r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'linux64-opt': (LinuxArtifactJob, (r'public/build/firefox-(.*)\.linux-x86_64\.tar\.bz2',
+                                       r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'linux64-debug': (LinuxArtifactJob, (r'public/build/target\.tar\.bz2',
+                                         r'public/build/target\.common\.tests\.zip')),
+    'macosx64-opt': (MacArtifactJob, (r'public/build/firefox-(.*)\.mac\.dmg',
+                                      r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'macosx64-debug': (MacArtifactJob, (r'public/build/firefox-(.*)\.mac64\.dmg',
+                                  r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'win32-opt': (WinArtifactJob, (r'public/build/firefox-(.*)\.win32.zip',
+                                   r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'win32-debug': (WinArtifactJob, (r'public/build/firefox-(.*)\.win32.zip',
+                               r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'win64-opt': (WinArtifactJob, (r'public/build/firefox-(.*)\.win64.zip',
+                                   r'public/build/firefox-(.*)\.common\.tests\.zip')),
+    'win64-debug': (WinArtifactJob, (r'public/build/firefox-(.*)\.win64.zip',
+                               r'public/build/firefox-(.*)\.common\.tests\.zip')),
 }
 
 
@@ -492,7 +490,7 @@ def cachedmethod(cachefunc):
     return decorator
 
 
-class CacheManager(object):
+class CacheManager:
     '''Maintain an LRU cache.  Provide simple persistence, including support for
     loading and saving the state using a "with" block.  Allow clearing the cache
     and printing the cache for debugging.
@@ -565,7 +563,7 @@ class CacheManager(object):
         # We use the persisted LRU caches to our advantage.  The first item is
         # most recent.
         with self:
-            item = next(self._cache.items(), None)
+            item = next(list(self._cache.items()), None)
             if item is not None:
                 (name, args, sorted_kwargs), result = item
                 self.print_last_item(args, sorted_kwargs, result)
@@ -593,10 +591,10 @@ class PushheadCache(CacheManager):
                          'changeset={changeset}&version=2&tipsonly=1')
         req = requests.get(cset_url_tmpl.format(tree=tree, changeset=revision),
                            headers={'Accept': 'application/json'})
-        if req.status_code not in range(200, 300):
+        if req.status_code not in list(range(200, 300)):
             raise ValueError
         result = req.json()
-        [found_pushid] = result['pushes'].keys()
+        [found_pushid] = list(result['pushes'].keys())
         return int(found_pushid)
 
     @cachedmethod(operator.attrgetter('_cache'))
@@ -692,7 +690,7 @@ class ArtifactCache(CacheManager):
             self.log(logging.INFO, 'artifact',
                 {'filename': value},
                 'Purged artifact {filename}')
-        except (OSError, IOError):
+        except OSError:
             pass
 
         try:
@@ -700,7 +698,7 @@ class ArtifactCache(CacheManager):
             self.log(logging.INFO, 'artifact',
                 {'filename': value + PROCESSED_SUFFIX},
                 'Purged processed artifact {filename}')
-        except (OSError, IOError):
+        except OSError:
             pass
 
     @cachedmethod(operator.attrgetter('_cache'))
@@ -760,7 +758,7 @@ class ArtifactCache(CacheManager):
             'Last installed binaries from local processed file {filename}')
 
 
-class Artifacts(object):
+class Artifacts:
     '''Maintain state to efficiently fetch build artifacts from a Firefox tree.'''
 
     def __init__(self, tree, substs, defines, job=None, log=None,
@@ -847,7 +845,7 @@ class Artifacts(object):
 
             candidate_pushheads = collections.defaultdict(list)
 
-            for tree, pushid in found_pushids.iteritems():
+            for tree, pushid in found_pushids.items():
                 end = pushid
                 start = pushid - NUM_PUSHHEADS_TO_QUERY_PER_PARENT
 
@@ -1052,7 +1050,7 @@ class Artifacts(object):
         """
         if source and os.path.isfile(source):
             return self.install_from_file(source, distdir)
-        elif source and urlparse.urlparse(source).scheme:
+        elif source and urllib.parse.urlparse(source).scheme:
             return self.install_from_url(source, distdir)
         else:
             if source is None and 'MOZ_ARTIFACT_REVISION' in os.environ:
diff --git a/python/mozbuild/mozbuild/backend/base.py b/python/mozbuild/mozbuild/backend/base.py
index 7ec5fe43d2..bad4e9ab3a 100644
--- a/python/mozbuild/mozbuild/backend/base.py
+++ b/python/mozbuild/mozbuild/backend/base.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 from abc import (
     ABCMeta,
@@ -30,7 +29,7 @@ from .configenvironment import ConfigEnvironment
 from mozbuild.base import ExecutionSummary
 
 
-class BuildBackend(LoggingMixin):
+class BuildBackend(LoggingMixin, metaclass=ABCMeta):
     """Abstract base class for build backends.
 
     A build backend is merely a consumer of the build configuration (the output
@@ -38,8 +37,6 @@ class BuildBackend(LoggingMixin):
     is the discretion of the specific implementation.
     """
 
-    __metaclass__ = ABCMeta
-
     def __init__(self, environment):
         assert isinstance(environment, ConfigEnvironment)
 
@@ -148,12 +145,12 @@ class BuildBackend(LoggingMixin):
         for path in delete_files:
             full_path = mozpath.join(self.environment.topobjdir, path)
             try:
-                with open(full_path, 'r') as existing:
+                with open(full_path) as existing:
                     old_content = existing.read()
                     if old_content:
                         self.file_diffs[full_path] = simple_diff(
                             full_path, old_content.splitlines(), None)
-            except IOError:
+            except OSError:
                 pass
             try:
                 if not self.dry_run:
@@ -162,7 +159,7 @@ class BuildBackend(LoggingMixin):
             except OSError:
                 pass
         # Remove now empty directories
-        for dir in set(mozpath.dirname(d) for d in delete_files):
+        for dir in {mozpath.dirname(d) for d in delete_files}:
             try:
                 os.removedirs(dir)
             except OSError:
@@ -204,7 +201,7 @@ class BuildBackend(LoggingMixin):
         return None
 
     @contextmanager
-    def _write_file(self, path=None, fh=None, mode='rU'):
+    def _write_file(self, path=None, fh=None, mode='r'):
         """Context manager to write a file.
 
         This is a glorified wrapper around FileAvoidWrite with integration to
@@ -252,7 +249,7 @@ class BuildBackend(LoggingMixin):
         srcdir = mozpath.dirname(obj.input_path)
         pp.context.update({
             k: ' '.join(v) if isinstance(v, list) else v
-            for k, v in obj.config.substs.iteritems()
+            for k, v in obj.config.substs.items()
         })
         pp.context.update(
             top_srcdir=obj.topsrcdir,
diff --git a/python/mozbuild/mozbuild/backend/common.py b/python/mozbuild/mozbuild/backend/common.py
index 351c6dbc81..400e3436b9 100644
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -2,9 +2,8 @@
 # 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, unicode_literals
 
-import cPickle as pickle
+import pickle
 import itertools
 import json
 import os
@@ -50,7 +49,7 @@ from collections import defaultdict
 
 from mozbuild.util import group_unified_files
 
-class XPIDLManager(object):
+class XPIDLManager:
     """Helps manage XPCOM IDLs in the context of the build system."""
     def __init__(self, config):
         self.config = config
@@ -93,7 +92,7 @@ class XPIDLManager(object):
             self.chrome_manifests.add(chrome_manifest)
 
 
-class WebIDLCollection(object):
+class WebIDLCollection:
     """Collects WebIDL info referenced during the build."""
 
     def __init__(self):
@@ -167,7 +166,7 @@ class WebIDLCollection(object):
         return [os.path.splitext(b)[0] for b in self.generated_events_basenames()]
 
 
-class TestManager(object):
+class TestManager:
     """Helps hold state related to tests."""
 
     def __init__(self, config):
@@ -199,7 +198,7 @@ class TestManager(object):
             self.manifest_defaults[sub_manifest] = defaults
 
     def add_installs(self, obj, topsrcdir):
-        for src, (dest, _) in obj.installs.iteritems():
+        for src, (dest, _) in obj.installs.items():
             key = src[len(topsrcdir)+1:]
             self.installs_by_path[key].append((src, dest))
         for src, pat, dest in obj.pattern_installs:
@@ -209,14 +208,14 @@ class TestManager(object):
             self.deferred_installs.add(path[2:])
 
 
-class BinariesCollection(object):
+class BinariesCollection:
     """Tracks state of binaries produced by the build."""
 
     def __init__(self):
         self.shared_libraries = []
         self.programs = []
 
-class IPDLCollection(object):
+class IPDLCollection:
     """Collects IPDL files during the build."""
 
     def __init__(self):
@@ -516,7 +515,7 @@ class CommonBackend(BuildBackend):
                 if '*' not in e.source and not os.path.exists(src.full_path):
                     if e.is_locale:
                         raise Exception(
-                            '%s: Cannot find %s' % (obj.path, e.source))
+                            '{}: Cannot find {}'.format(obj.path, e.source))
                     if e.source.startswith('/'):
                         src = Path(jar_context, '!' + e.source)
                     else:
diff --git a/python/mozbuild/mozbuild/backend/configenvironment.py b/python/mozbuild/mozbuild/backend/configenvironment.py
index 0edcf53660..737320855d 100644
--- a/python/mozbuild/mozbuild/backend/configenvironment.py
+++ b/python/mozbuild/mozbuild/backend/configenvironment.py
@@ -2,13 +2,13 @@
 # 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 os
 import sys
 
-from collections import Iterable
-from types import StringTypes, ModuleType
+from collections.abc import Iterable
+from types import ModuleType
+StringTypes = (str,)
 
 import mozpack.path as mozpath
 
@@ -16,13 +16,10 @@ from mozbuild.util import ReadOnlyDict
 from mozbuild.shellutil import quote as shell_quote
 
 
-if sys.version_info.major == 2:
-    text_type = unicode
-else:
-    text_type = str
+text_type = str
 
 
-class BuildConfig(object):
+class BuildConfig:
     """Represents the output of configure."""
 
     _CODE_CACHE = {}
@@ -51,7 +48,7 @@ class BuildConfig(object):
             mod.__file__ = path
             sys.modules['config.status'] = mod
 
-            with open(path, 'rt') as fh:
+            with open(path) as fh:
                 source = fh.read()
                 code_cache[path] = (
                     mtime,
@@ -73,7 +70,7 @@ class BuildConfig(object):
         return config
 
 
-class ConfigEnvironment(object):
+class ConfigEnvironment:
     """Perform actions associated with a configured but bare objdir.
 
     The purpose of this class is to preprocess files from the source directory
@@ -118,12 +115,18 @@ class ConfigEnvironment(object):
         if not source:
             source = mozpath.join(topobjdir, 'config.status')
         self.source = source
-        self.defines = ReadOnlyDict(defines or {})
-        self.non_global_defines = non_global_defines or []
-        self.substs = dict(substs or {})
-        self.topsrcdir = mozpath.abspath(topsrcdir)
-        self.topobjdir = mozpath.abspath(topobjdir)
-        self.mozconfig = mozpath.abspath(mozconfig) if mozconfig else None
+        def _decode(v):
+            if isinstance(v, bytes):
+                return v.decode('utf-8')
+            if isinstance(v, list):
+                return [_decode(i) for i in v]
+            return v
+        self.defines = ReadOnlyDict({_decode(k): _decode(v) for k, v in (defines or {}).items()})
+        self.non_global_defines = [_decode(x) for x in (non_global_defines or [])]
+        self.substs = {_decode(k): _decode(v) for k, v in (substs or {}).items()}
+        self.topsrcdir = mozpath.abspath(_decode(topsrcdir))
+        self.topobjdir = mozpath.abspath(_decode(topobjdir))
+        self.mozconfig = mozpath.abspath(_decode(mozconfig)) if mozconfig else None
         self.lib_prefix = self.substs.get('LIB_PREFIX', '')
         if 'LIB_SUFFIX' in self.substs:
             self.lib_suffix = '.%s' % self.substs['LIB_SUFFIX']
@@ -138,16 +141,18 @@ class ConfigEnvironment(object):
 
         global_defines = [name for name in self.defines
             if not name in self.non_global_defines]
-        self.substs['ACDEFINES'] = ' '.join(['-D%s=%s' % (name,
+        self.substs['ACDEFINES'] = ' '.join(['-D{}={}'.format(name,
             shell_quote(self.defines[name]).replace('$', '$$'))
             for name in sorted(global_defines)])
         def serialize(obj):
+            if isinstance(obj, bytes):
+                return obj.decode('utf-8')
             if isinstance(obj, StringTypes):
                 return obj
             if isinstance(obj, Iterable):
-                return ' '.join(obj)
+                return ' '.join(item.decode('utf-8') if isinstance(item, bytes) else item for item in obj)
             raise Exception('Unhandled type %s', type(obj))
-        self.substs['ALLSUBSTS'] = '\n'.join(sorted(['%s = %s' % (name,
+        self.substs['ALLSUBSTS'] = '\n'.join(sorted(['{} = {}'.format(name,
             serialize(self.substs[name])) for name in self.substs if self.substs[name]]))
         self.substs['ALLEMPTYSUBSTS'] = '\n'.join(sorted(['%s =' % name
             for name in self.substs if not self.substs[name]]))
diff --git a/python/mozbuild/mozbuild/backend/fastermake.py b/python/mozbuild/mozbuild/backend/fastermake.py
index 0ca385187b..af3f27b0f2 100644
--- a/python/mozbuild/mozbuild/backend/fastermake.py
+++ b/python/mozbuild/mozbuild/backend/fastermake.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals, print_function
 
 from mozbuild.backend.base import PartialBackend
 from mozbuild.backend.common import CommonBackend
@@ -24,7 +23,7 @@ import mozpack.path as mozpath
 
 class FasterMakeBackend(CommonBackend, PartialBackend):
     def _init(self):
-        super(FasterMakeBackend, self)._init()
+        super()._init()
 
         self._manifest_entries = OrderedDefaultDict(set)
 
@@ -128,14 +127,14 @@ class FasterMakeBackend(CommonBackend, PartialBackend):
         ):
             value = self.environment.substs.get(var)
             if value is not None:
-                mk.add_statement('%s = %s' % (var, value))
+                mk.add_statement('{} = {}'.format(var, value))
 
-        install_manifests_bases = self._install_manifests.keys()
+        install_manifests_bases = list(self._install_manifests.keys())
 
         # Add information for chrome manifest generation
         manifest_targets = []
 
-        for target, entries in self._manifest_entries.iteritems():
+        for target, entries in self._manifest_entries.items():
             manifest_targets.append(target)
             install_target = mozpath.basedir(target, install_manifests_bases)
             self._install_manifests[install_target].add_content(
@@ -144,16 +143,16 @@ class FasterMakeBackend(CommonBackend, PartialBackend):
 
         # Add information for install manifests.
         mk.add_statement('INSTALL_MANIFESTS = %s'
-                         % ' '.join(self._install_manifests.keys()))
+                         % ' '.join(list(self._install_manifests.keys())))
 
         # Add dependencies we infered:
-        for target, deps in self._dependencies.iteritems():
+        for target, deps in self._dependencies.items():
             mk.create_rule([target]).add_dependencies(
                 '$(TOPOBJDIR)/%s' % d for d in deps)
 
         mk.add_statement('include $(TOPSRCDIR)/config/faster/rules.mk')
 
-        for base, install_manifest in self._install_manifests.iteritems():
+        for base, install_manifest in self._install_manifests.items():
             with self._write_file(
                     mozpath.join(self.environment.topobjdir, 'faster',
                                  'install_%s' % base.replace('/', '_'))) as fh:
diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py
index 7f3b36c597..f5ac13769f 100644
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import logging
 import os
@@ -12,7 +11,7 @@ from collections import (
     defaultdict,
     namedtuple,
 )
-from StringIO import StringIO
+from io import StringIO
 from itertools import chain
 
 from mozpack.manifests import (
@@ -68,80 +67,81 @@ from ..util import (
 )
 from ..makeutil import Makefile
 from mozbuild.shellutil import quote as shell_quote
+from functools import reduce
 
 MOZBUILD_VARIABLES = [
-    b'ASFLAGS',
-    b'CMSRCS',
-    b'CMMSRCS',
-    b'CPP_UNIT_TESTS',
-    b'DIRS',
-    b'DIST_INSTALL',
-    b'EXTRA_DSO_LDOPTS',
-    b'EXTRA_JS_MODULES',
-    b'EXTRA_PP_COMPONENTS',
-    b'EXTRA_PP_JS_MODULES',
-    b'FORCE_SHARED_LIB',
-    b'FORCE_STATIC_LIB',
-    b'FINAL_LIBRARY',
-    b'HOST_CFLAGS',
-    b'HOST_CSRCS',
-    b'HOST_CMMSRCS',
-    b'HOST_CXXFLAGS',
-    b'HOST_EXTRA_LIBS',
-    b'HOST_LIBRARY_NAME',
-    b'HOST_PROGRAM',
-    b'HOST_SIMPLE_PROGRAMS',
-    b'IS_COMPONENT',
-    b'JAR_MANIFEST',
-    b'JAVA_JAR_TARGETS',
-    b'LD_VERSION_SCRIPT',
-    b'LIBRARY_NAME',
-    b'LIBS',
-    b'MAKE_FRAMEWORK',
-    b'MODULE',
-    b'NO_DIST_INSTALL',
-    b'NO_EXPAND_LIBS',
-    b'NO_INTERFACES_MANIFEST',
-    b'NO_JS_MANIFEST',
-    b'OS_LIBS',
-    b'PARALLEL_DIRS',
-    b'PREF_JS_EXPORTS',
-    b'PROGRAM',
-    b'PYTHON_UNIT_TESTS',
-    b'RESOURCE_FILES',
-    b'SDK_HEADERS',
-    b'SDK_LIBRARY',
-    b'SHARED_LIBRARY_LIBS',
-    b'SHARED_LIBRARY_NAME',
-    b'SIMPLE_PROGRAMS',
-    b'SONAME',
-    b'STATIC_LIBRARY_NAME',
-    b'TEST_DIRS',
-    b'TOOL_DIRS',
+    'ASFLAGS',
+    'CMSRCS',
+    'CMMSRCS',
+    'CPP_UNIT_TESTS',
+    'DIRS',
+    'DIST_INSTALL',
+    'EXTRA_DSO_LDOPTS',
+    'EXTRA_JS_MODULES',
+    'EXTRA_PP_COMPONENTS',
+    'EXTRA_PP_JS_MODULES',
+    'FORCE_SHARED_LIB',
+    'FORCE_STATIC_LIB',
+    'FINAL_LIBRARY',
+    'HOST_CFLAGS',
+    'HOST_CSRCS',
+    'HOST_CMMSRCS',
+    'HOST_CXXFLAGS',
+    'HOST_EXTRA_LIBS',
+    'HOST_LIBRARY_NAME',
+    'HOST_PROGRAM',
+    'HOST_SIMPLE_PROGRAMS',
+    'IS_COMPONENT',
+    'JAR_MANIFEST',
+    'JAVA_JAR_TARGETS',
+    'LD_VERSION_SCRIPT',
+    'LIBRARY_NAME',
+    'LIBS',
+    'MAKE_FRAMEWORK',
+    'MODULE',
+    'NO_DIST_INSTALL',
+    'NO_EXPAND_LIBS',
+    'NO_INTERFACES_MANIFEST',
+    'NO_JS_MANIFEST',
+    'OS_LIBS',
+    'PARALLEL_DIRS',
+    'PREF_JS_EXPORTS',
+    'PROGRAM',
+    'PYTHON_UNIT_TESTS',
+    'RESOURCE_FILES',
+    'SDK_HEADERS',
+    'SDK_LIBRARY',
+    'SHARED_LIBRARY_LIBS',
+    'SHARED_LIBRARY_NAME',
+    'SIMPLE_PROGRAMS',
+    'SONAME',
+    'STATIC_LIBRARY_NAME',
+    'TEST_DIRS',
+    'TOOL_DIRS',
     # XXX config/Makefile.in specifies this in a make invocation
     #'USE_EXTENSION_MANIFEST',
-    b'XPCSHELL_TESTS',
-    b'XPIDL_MODULE',
+    'XPCSHELL_TESTS',
+    'XPIDL_MODULE',
 ]
 
 DEPRECATED_VARIABLES = [
-    b'EXPORT_LIBRARY',
-    b'EXTRA_LIBS',
-    b'HOST_LIBS',
-    b'LIBXUL_LIBRARY',
-    b'MOCHITEST_A11Y_FILES',
-    b'MOCHITEST_BROWSER_FILES',
-    b'MOCHITEST_BROWSER_FILES_PARTS',
-    b'MOCHITEST_CHROME_FILES',
-    b'MOCHITEST_FILES',
-    b'MOCHITEST_FILES_PARTS',
-    b'MOCHITEST_METRO_FILES',
-    b'MOCHITEST_ROBOCOP_FILES',
-    b'MODULE_OPTIMIZE_FLAGS',
-    b'MOZ_CHROME_FILE_FORMAT',
-    b'SHORT_LIBNAME',
-    b'TESTING_JS_MODULES',
-    b'TESTING_JS_MODULE_DIR',
+    'EXPORT_LIBRARY',
+    'EXTRA_LIBS',
+    'HOST_LIBS',
+    'LIBXUL_LIBRARY',
+    'MOCHITEST_A11Y_FILES',
+    'MOCHITEST_BROWSER_FILES',
+    'MOCHITEST_BROWSER_FILES_PARTS',
+    'MOCHITEST_CHROME_FILES',
+    'MOCHITEST_FILES',
+    'MOCHITEST_FILES_PARTS',
+    'MOCHITEST_METRO_FILES',
+    'MOCHITEST_ROBOCOP_FILES',
+    'MODULE_OPTIMIZE_FLAGS',
+    'MOZ_CHROME_FILE_FORMAT',
+    'SHORT_LIBNAME',
+    'TESTING_JS_MODULES',
+    'TESTING_JS_MODULE_DIR',
 ]
 
 MOZBUILD_VARIABLES_MESSAGE = 'It should only be defined in moz.build files.'
@@ -153,10 +153,10 @@ DEPRECATED_VARIABLES_MESSAGE = (
 
 
 def make_quote(s):
-    return s.replace('#', '\#').replace('$', '$$')
+    return s.replace('#', r'\#').replace('$', '$$')
 
 
-class BackendMakeFile(object):
+class BackendMakeFile:
     """Represents a generated backend.mk file.
 
     This is both a wrapper around a file handle as well as a container that
@@ -200,7 +200,7 @@ class BackendMakeFile(object):
         self.fh.write(buf)
 
     def write_once(self, buf):
-        if isinstance(buf, unicode):
+        if isinstance(buf, str):
             buf = buf.encode('utf-8')
         if b'\n' + buf not in self.fh.getvalue():
             self.write(buf)
@@ -227,7 +227,7 @@ class BackendMakeFile(object):
         return self.fh.diff
 
 
-class RecursiveMakeTraversal(object):
+class RecursiveMakeTraversal:
     """
     Helper class to keep track of how the "traditional" recursive make backend
     recurses subdirectories. This is useful until all adhoc rules are removed
@@ -269,8 +269,8 @@ class RecursiveMakeTraversal(object):
         Helper function to call a filter from compute_dependencies and
         traverse.
         """
-        return filter(current, self._traversal.get(current,
-            self.SubDirectories()))
+        return list(filter(current, self._traversal.get(current,
+            self.SubDirectories())))
 
     def compute_dependencies(self, filter=None):
         """
@@ -329,11 +329,9 @@ class RecursiveMakeTraversal(object):
         if not start in self._traversal:
             return
         for node in parallel:
-            for n in self.traverse(node, filter):
-                yield n
+            yield from self.traverse(node, filter)
         for dir in sequential:
-            for d in self.traverse(dir, filter):
-                yield d
+            yield from self.traverse(dir, filter)
 
     def get_subdirs(self, dir):
         """
@@ -391,7 +389,7 @@ class RecursiveMakeBackend(CommonBackend):
         }
 
     def summary(self):
-        summary = super(RecursiveMakeBackend, self).summary()
+        summary = super().summary()
         summary.extend('; {makefile_in:d} -> {makefile_out:d} Makefile',
                        makefile_in=self._makefile_in_count,
                        makefile_out=self._makefile_out_count)
@@ -456,7 +454,7 @@ class RecursiveMakeBackend(CommonBackend):
             for f in sorted(obj.files):
                 f = mozpath.relpath(f, base)
                 for var in variables:
-                    backend_file.write('%s += %s\n' % (var, f))
+                    backend_file.write('{} += {}\n'.format(var, f))
         elif isinstance(obj, HostSources):
             suffix_map = {
                 '.c': 'HOST_CSRCS',
@@ -465,7 +463,7 @@ class RecursiveMakeBackend(CommonBackend):
             }
             var = suffix_map[obj.canonical_suffix]
             for f in sorted(obj.files):
-                backend_file.write('%s += %s\n' % (
+                backend_file.write('{} += {}\n'.format(
                     var, mozpath.relpath(f, backend_file.srcdir)))
         elif isinstance(obj, VariablePassthru):
             # Sorted so output is consistent and we don't bump mtimes.
@@ -476,12 +474,12 @@ class RecursiveMakeBackend(CommonBackend):
                 if isinstance(v, list):
                     for item in v:
                         backend_file.write(
-                            '%s += %s\n' % (k, make_quote(shell_quote(item))))
+                            '{} += {}\n'.format(k, make_quote(shell_quote(item))))
                 elif isinstance(v, bool):
                     if v:
                         backend_file.write('%s := 1\n' % k)
                 else:
-                    backend_file.write('%s := %s\n' % (k, v))
+                    backend_file.write('{} := {}\n'.format(k, v))
         elif isinstance(obj, HostDefines):
             self._process_defines(obj, backend_file, which='HOST_DEFINES')
         elif isinstance(obj, Defines):
@@ -499,10 +497,10 @@ class RecursiveMakeBackend(CommonBackend):
             self._no_skip[tier].add(backend_file.relobjdir)
             first_output = obj.outputs[0]
             dep_file = "%s.pp" % first_output
-            backend_file.write('%s:: %s\n' % (tier, first_output))
+            backend_file.write('{}:: {}\n'.format(tier, first_output))
             for output in obj.outputs:
                 if output != first_output:
-                    backend_file.write('%s: %s ;\n' % (output, first_output))
+                    backend_file.write('{}: {} ;\n'.format(output, first_output))
                 backend_file.write('GARBAGE += %s\n' % output)
             backend_file.write('EXTRA_MDDEPEND_FILES += %s\n' % dep_file)
             if obj.script:
@@ -645,17 +643,17 @@ class RecursiveMakeBackend(CommonBackend):
             for dir, deps in all_deps.items():
                 if deps is not None or (dir in self._idl_dirs \
                                         and tier == 'export'):
-                    rule = root_deps_mk.create_rule(['%s/%s' % (dir, tier)])
+                    rule = root_deps_mk.create_rule(['{}/{}'.format(dir, tier)])
                 if deps:
-                    rule.add_dependencies('%s/%s' % (d, tier) for d in deps if d)
+                    rule.add_dependencies('{}/{}'.format(d, tier) for d in deps if d)
                 if dir in self._idl_dirs and tier == 'export':
                     rule.add_dependencies(['xpcom/xpidl/%s' % tier])
             rule = root_deps_mk.create_rule(['recurse_%s' % tier])
             if main:
-                rule.add_dependencies('%s/%s' % (d, tier) for d in main)
+                rule.add_dependencies('{}/{}'.format(d, tier) for d in main)
 
         all_compile_deps = reduce(lambda x,y: x|y,
-            self._compile_graph.values()) if self._compile_graph else set()
+            list(self._compile_graph.values())) if self._compile_graph else set()
         compile_roots = set(self._compile_graph.keys()) - all_compile_deps
 
         rule = root_deps_mk.create_rule(['recurse_compile'])
@@ -670,7 +668,7 @@ class RecursiveMakeBackend(CommonBackend):
         # Fill root.mk with the convenience variables.
         for tier, filter in filters:
             all_dirs = self._traversal.traverse('', filter)
-            root_mk.add_statement('%s_dirs := %s' % (tier, ' '.join(all_dirs)))
+            root_mk.add_statement('{}_dirs := {}'.format(tier, ' '.join(all_dirs)))
 
         # Need a list of compile targets because we can't use pattern rules:
         # https://savannah.gnu.org/bugs/index.php?42833
@@ -701,7 +699,7 @@ class RecursiveMakeBackend(CommonBackend):
         makefile.add_statement(explanation)
 
         all_sources = ' '.join(source for source, _ in unified_source_mapping)
-        makefile.add_statement('%s := %s' % (unified_files_makefile_variable,
+        makefile.add_statement('{} := {}'.format(unified_files_makefile_variable,
                                              all_sources))
 
         if include_curdir_build_rules:
@@ -715,14 +713,14 @@ class RecursiveMakeBackend(CommonBackend):
             rule.add_dependencies(['$(CURDIR)/%: %'])
 
     def _check_blacklisted_variables(self, makefile_in, makefile_content):
-        if b'EXTERNALLY_MANAGED_MAKE_FILE' in makefile_content:
+        if 'EXTERNALLY_MANAGED_MAKE_FILE' in makefile_content:
             # Bypass the variable restrictions for externally managed makefiles.
             return
 
         for l in makefile_content.splitlines():
             l = l.strip()
             # Don't check comments
-            if l.startswith(b'#'):
+            if l.startswith('#'):
                 continue
             for x in chain(MOZBUILD_VARIABLES, DEPRECATED_VARIABLES):
                 if x not in l:
@@ -779,11 +777,11 @@ class RecursiveMakeBackend(CommonBackend):
                     # Skip every directory but those with a Makefile
                     # containing a tools target, or XPI_PKGNAME or
                     # INSTALL_EXTENSION_ID.
-                    for t in (b'XPI_PKGNAME', b'INSTALL_EXTENSION_ID',
-                            b'tools'):
+                    for t in ('XPI_PKGNAME', 'INSTALL_EXTENSION_ID',
+                            'tools'):
                         if t not in content:
                             continue
-                        if t == b'tools' and not re.search('(?:^|\s)tools.*::', content, re.M):
+                        if t == 'tools' and not re.search(r'(?:^|\s)tools.*::', content, re.M):
                             continue
                         if objdir == self.environment.topobjdir:
                             continue
@@ -849,12 +847,12 @@ class RecursiveMakeBackend(CommonBackend):
                                           obj.unified_source_mapping,
                                           unified_files_makefile_variable=var,
                                           include_curdir_build_rules=False)
-            backend_file.write('%s += $(%s)\n' % (non_unified_var, var))
+            backend_file.write('{} += $({})\n'.format(non_unified_var, var))
         else:
             # Sorted so output is consistent and we don't bump mtimes.
             source_files = list(sorted(obj.files))
 
-            backend_file.write('%s += %s\n' % (
+            backend_file.write('{} += {}\n'.format(
                     non_unified_var, ' '.join(source_files)))
 
     def _process_directory_traversal(self, obj, backend_file):
@@ -879,7 +877,7 @@ class RecursiveMakeBackend(CommonBackend):
         defines = list(obj.get_defines())
         if defines:
             defines = ' '.join(shell_quote(d) for d in defines)
-            backend_file.write_once('%s += %s\n' % (which, defines))
+            backend_file.write_once('{} += {}\n'.format(which, defines))
 
     def _process_installation_target(self, obj, backend_file):
         # A few makefiles need to be able to override the following rules via
@@ -934,9 +932,9 @@ class RecursiveMakeBackend(CommonBackend):
             # listing the .idls here, we ensure the make file has a
             # reference to the new .idl. Since the new .idl presumably has
             # an mtime newer than the .xpt, it will trigger xpt generation.
-            xpt_path = '$(DEPTH)/%s/components/%s.xpt' % (install_target, module)
+            xpt_path = '$(DEPTH)/{}/components/{}.xpt'.format(install_target, module)
             xpt_files.add(xpt_path)
-            mk.add_statement('%s_deps = %s' % (module, ' '.join(deps)))
+            mk.add_statement('{}_deps = {}'.format(module, ' '.join(deps)))
 
             if install_target.startswith('dist/'):
                 path = mozpath.relpath(xpt_path, '$(DEPTH)/dist')
@@ -1064,12 +1062,12 @@ class RecursiveMakeBackend(CommonBackend):
 
     def _process_per_source_flag(self, per_source_flag, backend_file):
         for flag in per_source_flag.flags:
-            backend_file.write('%s_FLAGS += %s\n' % (mozpath.basename(per_source_flag.file_name), flag))
+            backend_file.write('{}_FLAGS += {}\n'.format(mozpath.basename(per_source_flag.file_name), flag))
 
     def _process_java_jar_data(self, jar, backend_file):
         target = jar.name
         backend_file.write('JAVA_JAR_TARGETS += %s\n' % target)
-        backend_file.write('%s_DEST := %s.jar\n' % (target, jar.name))
+        backend_file.write('{}_DEST := {}.jar\n'.format(target, jar.name))
         if jar.sources:
             backend_file.write('%s_JAVAFILES := %s\n' %
                 (target, ' '.join(jar.sources)))
@@ -1112,7 +1110,7 @@ class RecursiveMakeBackend(CommonBackend):
         backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
 
     def _build_target_for_obj(self, obj):
-        return '%s/%s' % (mozpath.relpath(obj.objdir,
+        return '{}/{}'.format(mozpath.relpath(obj.objdir,
             self.environment.topobjdir), obj.KIND)
 
     def _process_linked_libraries(self, obj, backend_file):
@@ -1219,7 +1217,7 @@ class RecursiveMakeBackend(CommonBackend):
                         install_manifest.add_symlink(f.full_path, dest)
                 else:
                     install_manifest.add_optional_exists(dest)
-                    backend_file.write('%s_FILES += %s\n' % (
+                    backend_file.write('{}_FILES += {}\n'.format(
                         target_var, self._pretty_path(f, backend_file)))
                     have_objdir_files = True
             if have_objdir_files:
@@ -1228,7 +1226,7 @@ class RecursiveMakeBackend(CommonBackend):
                 backend_file.write('%s_DEST := $(DEPTH)/%s\n'
                                    % (target_var,
                                       mozpath.join(target, path)))
-                backend_file.write('%s_TARGET := %s\n' % (target_var, tier))
+                backend_file.write('{}_TARGET := {}\n'.format(target_var, tier))
                 backend_file.write('INSTALL_TARGETS += %s\n' % target_var)
 
     def _process_final_target_pp_files(self, obj, files, backend_file, name):
@@ -1244,7 +1242,7 @@ class RecursiveMakeBackend(CommonBackend):
             self._no_skip['misc'].add(backend_file.relobjdir)
             var = '%s_%d' % (name, i)
             for f in files:
-                backend_file.write('%s += %s\n' % (
+                backend_file.write('{} += {}\n'.format(
                     var, self._pretty_path(f, backend_file)))
             backend_file.write('%s_PATH := $(DEPTH)/%s\n'
                                % (var, mozpath.join(obj.install_target, path)))
@@ -1303,7 +1301,7 @@ class RecursiveMakeBackend(CommonBackend):
             for manifest in sorted(manifests):
                 master.write('[include:%s]\n' % manifest)
 
-    class Substitution(object):
+    class Substitution:
         """BaseConfigSubstitution-like class for use with _create_makefile."""
         __slots__ = (
             'input_path',
@@ -1326,20 +1324,20 @@ class RecursiveMakeBackend(CommonBackend):
                 pp.context.update(extra)
             if not pp.context.get('autoconfmk', ''):
                 pp.context['autoconfmk'] = 'autoconf.mk'
-            pp.handleLine(b'# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.\n');
-            pp.handleLine(b'DEPTH := @DEPTH@\n')
-            pp.handleLine(b'topobjdir := @topobjdir@\n')
-            pp.handleLine(b'topsrcdir := @top_srcdir@\n')
-            pp.handleLine(b'srcdir := @srcdir@\n')
-            pp.handleLine(b'VPATH := @srcdir@\n')
-            pp.handleLine(b'relativesrcdir := @relativesrcdir@\n')
-            pp.handleLine(b'include $(DEPTH)/config/@autoconfmk@\n')
+            pp.handleLine('# THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.\n');
+            pp.handleLine('DEPTH := @DEPTH@\n')
+            pp.handleLine('topobjdir := @topobjdir@\n')
+            pp.handleLine('topsrcdir := @top_srcdir@\n')
+            pp.handleLine('srcdir := @srcdir@\n')
+            pp.handleLine('VPATH := @srcdir@\n')
+            pp.handleLine('relativesrcdir := @relativesrcdir@\n')
+            pp.handleLine('include $(DEPTH)/config/@autoconfmk@\n')
             if not stub:
                 pp.do_include(obj.input_path)
             # Empty line to avoid failures when last line in Makefile.in ends
             # with a backslash.
-            pp.handleLine(b'\n')
-            pp.handleLine(b'include $(topsrcdir)/config/recurse.mk\n')
+            pp.handleLine('\n')
+            pp.handleLine('include $(topsrcdir)/config/recurse.mk\n')
         if not stub:
             # Adding the Makefile.in here has the desired side-effect
             # that if the Makefile.in disappears, this will force
@@ -1367,15 +1365,15 @@ class RecursiveMakeBackend(CommonBackend):
                     '$< -o $@)'
             ])
 
-        mk.add_statement('ALL_IPDLSRCS := %s %s' % (' '.join(sorted_nonstatic_ipdl_basenames),
+        mk.add_statement('ALL_IPDLSRCS := {} {}'.format(' '.join(sorted_nonstatic_ipdl_basenames),
                          ' '.join(sorted_static_ipdl_sources)))
 
         self._add_unified_build_rules(mk, unified_ipdl_cppsrcs_mapping,
                                       unified_files_makefile_variable='CPPSRCS')
 
         # Preprocessed ipdl files are generated in ipdl_dir.
-        mk.add_statement('IPDLDIRS := %s %s' % (ipdl_dir, ' '.join(sorted(set(mozpath.dirname(p)
-            for p in sorted_static_ipdl_sources)))))
+        mk.add_statement('IPDLDIRS := {} {}'.format(ipdl_dir, ' '.join(sorted({mozpath.dirname(p)
+            for p in sorted_static_ipdl_sources}))))
 
         with self._write_file(mozpath.join(ipdl_dir, 'ipdlsrcs.mk')) as ipdls:
             mk.dump(ipdls, removal_guard=False)
diff --git a/python/mozbuild/mozbuild/backend/tup.py b/python/mozbuild/mozbuild/backend/tup.py
index b148532c89..adb4f172e7 100644
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import os
 
@@ -26,7 +25,7 @@ from ..util import (
 )
 
 
-class BackendTupfile(object):
+class BackendTupfile:
     """Represents a generated Tupfile.
     """
 
@@ -72,13 +71,13 @@ class BackendTupfile(object):
         else:
             caret_text = flags
 
-        self.write(': %(inputs)s |> %(display)s%(cmd)s |> %(outputs)s%(extra_outputs)s\n' % {
-            'inputs': ' '.join(inputs),
-            'display': '^%s^ ' % caret_text if caret_text else '',
-            'cmd': ' '.join(cmd),
-            'outputs': ' '.join(outputs),
-            'extra_outputs': ' | ' + ' '.join(extra_outputs) if extra_outputs else '',
-        })
+        self.write(': {inputs} |> {display}{cmd} |> {outputs}{extra_outputs}\n'.format(
+            inputs=' '.join(inputs),
+            display='^%s^ ' % caret_text if caret_text else '',
+            cmd=' '.join(cmd),
+            outputs=' '.join(outputs),
+            extra_outputs=' | ' + ' '.join(extra_outputs) if extra_outputs else '',
+        ))
 
     def export_shell(self):
         if not self.shell_exported:
@@ -182,7 +181,7 @@ class TupOnly(CommonBackend, PartialBackend):
         with self._write_file(mozpath.join(self.environment.topobjdir, 'Tuprules.tup')) as fh:
             acdefines = [name for name in self.environment.defines
                 if not name in self.environment.non_global_defines]
-            acdefines_flags = ' '.join(['-D%s=%s' % (name,
+            acdefines_flags = ' '.join(['-D{}={}'.format(name,
                 shell_quote(self.environment.defines[name]))
                 for name in sorted(acdefines)])
             # TODO: AB_CD only exists in Makefiles at the moment.
@@ -253,7 +252,7 @@ class TupOnly(CommonBackend, PartialBackend):
         backend_file = self._get_backend_file('xpcom/xpidl')
         backend_file.export_shell()
 
-        for module, data in sorted(manager.modules.iteritems()):
+        for module, data in sorted(manager.modules.items()):
             dest, idls = data
             cmd = [
                 '$(PYTHON_PATH)',
@@ -269,7 +268,7 @@ class TupOnly(CommonBackend, PartialBackend):
             ]
             cmd.extend(sorted(idls))
 
-            outputs = ['$(MOZ_OBJ_ROOT)/%s/components/%s.xpt' % (dest, module)]
+            outputs = ['$(MOZ_OBJ_ROOT)/{}/components/{}.xpt'.format(dest, module)]
             outputs.extend(['$(MOZ_OBJ_ROOT)/dist/include/%s.h' % f for f in sorted(idls)])
             backend_file.rule(
                 inputs=[
diff --git a/python/mozbuild/mozbuild/base.py b/python/mozbuild/mozbuild/base.py
index 24791b6182..273b9cc353 100644
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 import json
 import logging
 import mozpack.path as mozpath
@@ -61,7 +61,7 @@ class ObjdirMismatchException(BadEnvironmentException):
         self.objdir2 = objdir2
 
     def __str__(self):
-        return "Objdir mismatch: %s != %s" % (self.objdir1, self.objdir2)
+        return "Objdir mismatch: {} != {}".format(self.objdir1, self.objdir2)
 
 
 class MozbuildObject(ProcessExecutionMixin):
@@ -126,7 +126,7 @@ class MozbuildObject(ProcessExecutionMixin):
         mozconfig = MozconfigLoader.AUTODETECT
 
         def load_mozinfo(path):
-            info = json.load(open(path, 'rt'))
+            info = json.load(open(path))
             topsrcdir = info.get('topsrcdir')
             topobjdir = os.path.dirname(path)
             mozconfig = info.get('mozconfig')
@@ -368,7 +368,7 @@ class MozbuildObject(ProcessExecutionMixin):
         args = o._normalize_command([p], True)
 
         _config_guess_output.append(
-                subprocess.check_output(args, cwd=self.topsrcdir).strip())
+                subprocess.check_output(args, cwd=self.topsrcdir).strip().decode('utf-8', errors='replace'))
         return _config_guess_output[0]
 
     def notify(self, msg):
@@ -430,7 +430,7 @@ class MozbuildObject(ProcessExecutionMixin):
                 FlashWindowEx(params)
         except Exception as e:
             self.log(logging.WARNING, 'notifier-failed', {'error':
-                e.message}, 'Notification center failed: {error}')
+                str(e)}, 'Notification center failed: {error}')
 
     def _ensure_objdir_exists(self):
         if os.path.isdir(self.statedir):
@@ -489,7 +489,7 @@ class MozbuildObject(ProcessExecutionMixin):
             for flag in flags:
                 if flag == '-j':
                     try:
-                        flag = flags.next()
+                        flag = next(flags)
                     except StopIteration:
                         break
                     try:
@@ -534,7 +534,7 @@ class MozbuildObject(ProcessExecutionMixin):
             fn = self._run_command_in_srcdir
 
         append_env = dict(append_env or ())
-        append_env[b'MACH'] = '1'
+        append_env['MACH'] = '1'
 
         params = {
             'args': args,
@@ -674,19 +674,19 @@ class MachCommandBase(MozbuildObject):
         except BuildEnvironmentNotFoundException:
             pass
         except ObjdirMismatchException as e:
-            print('Ambiguous object directory detected. We detected that '
+            print(('Ambiguous object directory detected. We detected that '
                 'both %s and %s could be object directories. This is '
                 'typically caused by having a mozconfig pointing to a '
                 'different object directory from the current working '
                 'directory. To solve this problem, ensure you do not have a '
                 'default mozconfig in searched paths.' % (e.objdir1,
-                    e.objdir2))
+                    e.objdir2)))
             sys.exit(1)
 
         except MozconfigLoadException as e:
-            print('Error loading mozconfig: ' + e.path)
+            print(('Error loading mozconfig: ' + e.path))
             print('')
-            print(e.message)
+            print((e.message))
             if e.output:
                 print('')
                 print('mozconfig output:')
@@ -708,13 +708,13 @@ class MachCommandBase(MozbuildObject):
             self.mozconfig
 
         except MozconfigFindException as e:
-            print(e.message)
+            print((e.message))
             sys.exit(1)
 
         except MozconfigLoadException as e:
-            print('Error loading mozconfig: ' + e.path)
+            print(('Error loading mozconfig: ' + e.path))
             print('')
-            print(e.message)
+            print((e.message))
             if e.output:
                 print('')
                 print('mozconfig output:')
@@ -732,14 +732,14 @@ class MachCommandBase(MozbuildObject):
             self._ensure_state_subdir_exists('.')
             logfile = self._get_state_filename('last_log.json')
             try:
-                fd = open(logfile, "wb")
+                fd = open(logfile, "w")
                 self.log_manager.add_json_handler(fd)
             except Exception as e:
                 self.log(logging.WARNING, 'mach', {'error': e},
                          'Log will not be kept for this command: {error}.')
 
 
-class MachCommandConditions(object):
+class MachCommandConditions:
     """A series of commonly used condition functions which can be applied to
     mach commands with providers deriving from MachCommandBase.
     """
@@ -793,7 +793,7 @@ class MachCommandConditions(object):
         return False
 
 
-class PathArgument(object):
+class PathArgument:
     """Parse a filesystem path argument and transform it in various ways."""
 
     def __init__(self, arg, topsrcdir, topobjdir, cwd=None):
diff --git a/python/mozbuild/mozbuild/compilation/codecomplete.py b/python/mozbuild/mozbuild/compilation/codecomplete.py
index 05583961a5..3ad5ca0d1a 100644
--- a/python/mozbuild/mozbuild/compilation/codecomplete.py
+++ b/python/mozbuild/mozbuild/compilation/codecomplete.py
@@ -4,8 +4,8 @@
 
 # This modules provides functionality for dealing with code completion.
 
-from __future__ import absolute_import
 
+from __future__ import print_function
 import os
 
 from mach.decorators import (
@@ -59,5 +59,5 @@ class Introspection(MachCommandBase):
         # Drop the first flag since that is the pathname of the compiler.
         flags = (shell_split(build_vars[cc]) + shell_split(build_vars[name]))[1:]
 
-        print(' '.join(shell_quote(arg)
-                       for arg in util.sanitize_cflags(flags)))
+        print((' '.join(shell_quote(arg)
+                       for arg in util.sanitize_cflags(flags))))
diff --git a/python/mozbuild/mozbuild/compilation/database.py b/python/mozbuild/mozbuild/compilation/database.py
index 20b09df488..4b3978a937 100644
--- a/python/mozbuild/mozbuild/compilation/database.py
+++ b/python/mozbuild/mozbuild/compilation/database.py
@@ -118,7 +118,7 @@ class CompileDBBackend(CommonBackend):
 
         db = []
 
-        for (directory, filename), cmd in self._db.iteritems():
+        for (directory, filename), cmd in self._db.items():
             env = self._envs[directory]
             cmd = list(cmd)
             cmd.append(filename)
@@ -151,7 +151,7 @@ class CompileDBBackend(CommonBackend):
                 a = expand_variables(a, variables).split()
                 if not a:
                     continue
-                if isinstance(a, types.StringTypes):
+                if isinstance(a, (str,)):
                     c.append(a)
                 else:
                     c.extend(a)
@@ -216,7 +216,7 @@ class CompileDBBackend(CommonBackend):
             value = cenv.substs.get(name)
             if not value:
                 return
-            if isinstance(value, types.StringTypes):
+            if isinstance(value, (str,)):
                 value = value.split()
             db.extend(value)
 
diff --git a/python/mozbuild/mozbuild/compilation/util.py b/python/mozbuild/mozbuild/compilation/util.py
index 32ff2f8767..0f980e9a58 100644
--- a/python/mozbuild/mozbuild/compilation/util.py
+++ b/python/mozbuild/mozbuild/compilation/util.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 from mozbuild import shellutil
 
diff --git a/python/mozbuild/mozbuild/compilation/warnings.py b/python/mozbuild/mozbuild/compilation/warnings.py
index 8fb20ccbff..8fd16fb4c7 100644
--- a/python/mozbuild/mozbuild/compilation/warnings.py
+++ b/python/mozbuild/mozbuild/compilation/warnings.py
@@ -4,7 +4,6 @@
 
 # This modules provides functionality for dealing with compiler warnings.
 
-from __future__ import absolute_import, unicode_literals
 
 import errno
 import json
@@ -94,7 +93,7 @@ class CompilerWarning(dict):
         return hash(tuple(sorted(self.items())))
 
 
-class WarningsDatabase(object):
+class WarningsDatabase:
     """Holds a collection of warnings.
 
     The warnings database is a semi-intelligent container that holds warnings
@@ -130,8 +129,7 @@ class WarningsDatabase(object):
 
     def __iter__(self):
         for value in self._files.values():
-            for warning in value['warnings']:
-                yield warning
+            yield from value['warnings']
 
     def __contains__(self, item):
         for value in self._files.values():
@@ -145,8 +143,7 @@ class WarningsDatabase(object):
     def warnings(self):
         """All the CompilerWarning instances in this database."""
         for value in self._files.values():
-            for w in value['warnings']:
-                yield w
+            yield from value['warnings']
 
     def type_counts(self, dirpath=None):
         """Returns a mapping of warning types to their counts."""
@@ -172,8 +169,7 @@ class WarningsDatabase(object):
         """Obtain the warnings for the specified file."""
         f = self._files.get(filename, {'warnings': []})
 
-        for warning in f['warnings']:
-            yield warning
+        yield from f['warnings']
 
     def insert(self, warning, compute_hash=True):
         assert isinstance(warning, CompilerWarning)
@@ -210,7 +206,7 @@ class WarningsDatabase(object):
         """
 
         # Need to calculate up front since we are mutating original object.
-        filenames = self._files.keys()
+        filenames = list(self._files.keys())
         for filename in filenames:
             if not os.path.exists(filename):
                 del self._files[filename]
@@ -229,10 +225,10 @@ class WarningsDatabase(object):
         obj = {'files': {}}
 
         # All this hackery because JSON can't handle sets.
-        for k, v in self._files.iteritems():
+        for k, v in self._files.items():
             obj['files'][k] = {}
 
-            for k2, v2 in v.iteritems():
+            for k2, v2 in v.items():
                 normalized = v2
 
                 if k2 == 'warnings':
@@ -249,8 +245,8 @@ class WarningsDatabase(object):
         self._files = obj['files']
 
         # Normalize data types.
-        for filename, value in self._files.iteritems():
-            for k, v in value.iteritems():
+        for filename, value in self._files.items():
+            for k, v in value.items():
                 if k != 'warnings':
                     continue
 
@@ -275,11 +271,11 @@ class WarningsDatabase(object):
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
-        with open(filename, 'wb') as fh:
+        with open(filename, 'w') as fh:
             self.serialize(fh)
 
 
-class WarningsCollector(object):
+class WarningsCollector:
     """Collects warnings from text data.
 
     Instances of this class receive data (usually the output of compiler
diff --git a/python/mozbuild/mozbuild/config_status.py b/python/mozbuild/mozbuild/config_status.py
index 80725fcc56..584e643e1d 100644
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -6,7 +6,6 @@
 # drop-in replacement for autoconf 2.13's config.status, with features
 # borrowed from autoconf > 2.5, and additional features.
 
-from __future__ import absolute_import, print_function
 
 import logging
 import os
@@ -63,7 +62,11 @@ def config_status(topobjdir='.', topsrcdir='.', defines=None,
             '%s' % topsrcdir)
 
     default_backends = ['RecursiveMake']
-    default_backends = (substs or {}).get('BUILD_BACKENDS', ['RecursiveMake'])
+    _raw_backends = (substs or {}).get('BUILD_BACKENDS') or \
+                    (substs or {}).get(b'BUILD_BACKENDS')
+    if _raw_backends is not None:
+        default_backends = [v.decode() if isinstance(v, bytes) else v
+                            for v in _raw_backends]
 
     parser = ArgumentParser()
     parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
@@ -93,7 +96,7 @@ def config_status(topobjdir='.', topsrcdir='.', defines=None,
     if 'WRITE_MOZINFO' in os.environ:
         write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
 
-    cpu_start = time.clock()
+    cpu_start = time.perf_counter()
     time_start = time.time()
 
     # Make appropriate backend instances, defaulting to RecursiveMakeBackend,
@@ -142,7 +145,7 @@ def config_status(topobjdir='.', topsrcdir='.', defines=None,
         'Whistling in the dark',
     ]
 
-    print('{0}...'.format(random.choice(STATUS_MESSAGES)), file=sys.stderr)
+    print('{}...'.format(random.choice(STATUS_MESSAGES)), file=sys.stderr)
     sys.stderr.flush()
 
     if len(selected_backends) > 1:
@@ -157,7 +160,7 @@ def config_status(topobjdir='.', topsrcdir='.', defines=None,
         print(summary, file=sys.stderr)
         execution_time += summary.execution_time
 
-    cpu_time = time.clock() - cpu_start
+    cpu_time = time.perf_counter() - cpu_start
     wall_time = time.time() - time_start
     efficiency = cpu_time / wall_time if wall_time else 100
     untracked = wall_time - execution_time
diff --git a/python/mozbuild/mozbuild/configure/__init__.py b/python/mozbuild/mozbuild/configure/__init__.py
index a59876fcae..d7260cf52c 100644
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import inspect
 import logging
@@ -43,14 +42,14 @@ class ConfigureError(Exception):
     pass
 
 
-class SandboxDependsFunction(object):
+class SandboxDependsFunction:
     '''Sandbox-visible representation of @depends functions.'''
     def __call__(self, *arg, **kwargs):
         raise ConfigureError('The `%s` function may not be called'
                              % self.__name__)
 
 
-class DependsFunction(object):
+class DependsFunction:
     __slots__ = (
         'func', 'dependencies', 'when', 'sandboxed', 'sandbox', '_result')
 
@@ -90,7 +89,7 @@ class DependsFunction(object):
         return self.func(*resolved_args)
 
     def __repr__(self):
-        return '<%s.%s %s(%s)>' % (
+        return '<{}.{} {}({})>'.format(
             self.__class__.__module__,
             self.__class__.__name__,
             self.name,
@@ -122,7 +121,7 @@ class CombinedDependsFunction(DependsFunction):
                 flatten_deps.insert(0, sandbox._help_option)
                 break
 
-        super(CombinedDependsFunction, self).__init__(
+        super().__init__(
             sandbox, wrapper, flatten_deps)
 
     @memoized_property
@@ -142,6 +141,9 @@ class CombinedDependsFunction(DependsFunction):
     def __ne__(self, other):
         return not self == other
 
+    def __hash__(self):
+        return id(self)
+
 class SandboxedGlobal(dict):
     '''Identifiable dict type for use as function global'''
 
@@ -192,9 +194,10 @@ class ConfigureSandbox(dict):
         b: __builtins__[b]
         for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
                   'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
-                  'hasattr', 'enumerate', 'range', 'zip', '__build_class__')
+                  'hasattr', 'enumerate', 'range', 'zip', '__build_class__',
+                  'exec')
         if b in __builtins__},
-    __import__=forbidden_import, str=unicode)
+    __import__=forbidden_import, str=str)
 
     # Expose a limited set of functions from os.path
     OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{
@@ -268,7 +271,7 @@ class ConfigureSandbox(dict):
                 return method
             def wrapped(*args, **kwargs):
                 out_args = [
-                    arg.decode(encoding) if isinstance(arg, str) else arg
+                    arg.decode(encoding) if isinstance(arg, bytes) else arg
                     for arg in args
                 ]
                 return method(*out_args, **kwargs)
@@ -334,7 +337,7 @@ class ConfigureSandbox(dict):
         if path:
             self.include_file(path)
 
-        for option in self._options.itervalues():
+        for option in self._options.values():
             # All options must be referenced by some @depends function
             if option not in self._seen:
                 raise ConfigureError(
@@ -373,7 +376,7 @@ class ConfigureSandbox(dict):
         if func:
             return func
 
-        return super(ConfigureSandbox, self).__getitem__(key)
+        return super().__getitem__(key)
 
     def __setitem__(self, key, value):
         if (key in self.BUILTINS or key == '__builtins__' or
@@ -389,7 +392,7 @@ class ConfigureSandbox(dict):
             raise KeyError('Cannot assign `%s` because it is neither a '
                            '@depends nor a @template' % key)
 
-        return super(ConfigureSandbox, self).__setitem__(key, value)
+        return super().__setitem__(key, value)
 
     def _resolve(self, arg, need_help_dependency=True):
         if isinstance(arg, SandboxDependsFunction):
@@ -438,7 +441,7 @@ class ConfigureSandbox(dict):
                     value = PositiveOptionValue()
                 elif value is False or value == ():
                     value = NegativeOptionValue()
-                elif isinstance(value, types.StringTypes):
+                elif isinstance(value, (str,)):
                     value = PositiveOptionValue((value,))
                 elif isinstance(value, tuple):
                     value = PositiveOptionValue(value)
@@ -478,7 +481,7 @@ class ConfigureSandbox(dict):
         return value
 
     def _dependency(self, arg, callee_name, arg_name=None):
-        if isinstance(arg, types.StringTypes):
+        if isinstance(arg, (str,)):
             prefix, name, values = Option.split_option(arg)
             if values != ():
                 raise ConfigureError("Option must not contain an '='")
@@ -542,7 +545,7 @@ class ConfigureSandbox(dict):
         '''
         when = self._normalize_when(kwargs.get('when'), 'option')
         args = [self._resolve(arg) for arg in args]
-        kwargs = {k: self._resolve(v) for k, v in kwargs.iteritems()
+        kwargs = {k: self._resolve(v) for k, v in kwargs.items()
                                       if k != 'when'}
         option = Option(*args, **kwargs)
         if when:
@@ -623,7 +626,7 @@ class ConfigureSandbox(dict):
         with self.only_when_impl(when):
             what = self._resolve(what)
             if what:
-                if not isinstance(what, types.StringTypes):
+                if not isinstance(what, (str,)):
                     raise TypeError("Unexpected type: '%s'" % type(what).__name__)
                 self.include_file(what)
 
@@ -641,7 +644,7 @@ class ConfigureSandbox(dict):
             (k[:-len('_impl')], getattr(self, k))
             for k in dir(self) if k.endswith('_impl') and k != 'template_impl'
         )
-        glob.update((k, v) for k, v in self.iteritems() if k not in glob)
+        glob.update((k, v) for k, v in self.items() if k not in glob)
 
         # Any function argument to the template must be prepared to be sandboxed.
         # If the template itself returns a function (in which case, it's very
@@ -665,7 +668,7 @@ class ConfigureSandbox(dict):
             def wrapper(*args, **kwargs):
                 args = [maybe_prepare_function(arg) for arg in args]
                 kwargs = {k: maybe_prepare_function(v)
-                          for k, v in kwargs.iteritems()}
+                          for k, v in kwargs.items()}
                 ret = template(*args, **kwargs)
                 if isfunction(ret):
                     # We can't expect the sandboxed code to think about all the
@@ -684,7 +687,7 @@ class ConfigureSandbox(dict):
         self._templates.add(wrapper)
         return wrapper
 
-    RE_MODULE = re.compile('^[a-zA-Z0-9_\.]+$')
+    RE_MODULE = re.compile(r'^[a-zA-Z0-9_\.]+$')
 
     def imports_impl(self, _import, _from=None, _as=None):
         '''Implementation of @imports.
@@ -697,7 +700,7 @@ class ConfigureSandbox(dict):
         for value, required in (
                 (_import, True), (_from, False), (_as, False)):
 
-            if not isinstance(value, types.StringTypes) and (
+            if not isinstance(value, (str,)) and (
                     required or value is not None):
                 raise TypeError("Unexpected type: '%s'" % type(value).__name__)
             if value is not None and not self.RE_MODULE.match(value):
@@ -725,10 +728,10 @@ class ConfigureSandbox(dict):
         for _from, _import, _as in self._imports.get(func, ()):
             _from = '%s.' % _from if _from else ''
             if _as:
-                glob[_as] = self._get_one_import('%s%s' % (_from, _import))
+                glob[_as] = self._get_one_import('{}{}'.format(_from, _import))
             else:
                 what = _import.split('.')[0]
-                glob[what] = self._get_one_import('%s%s' % (_from, what))
+                glob[what] = self._get_one_import('{}{}'.format(_from, what))
 
     def _get_one_import(self, what):
         # The special `__sandbox__` module gives access to the sandbox
@@ -738,8 +741,12 @@ class ConfigureSandbox(dict):
         # Special case for the open() builtin, because otherwise, using it
         # fails with "IOError: file() constructor not accessible in
         # restricted mode"
-        if what == '__builtin__.open':
+        if what in ('__builtin__.open', 'builtins.open'):
             return lambda *args, **kwargs: open(*args, **kwargs)
+        # Python 3: __builtin__ was renamed to builtins
+        what = what.replace('__builtin__.', 'builtins.')
+        if what == '__builtin__':
+            what = 'builtins'
         # Until this proves to be a performance problem, just construct an
         # import statement and execute it.
         import_line = ''
@@ -760,7 +767,7 @@ class ConfigureSandbox(dict):
         name = self._resolve(name, need_help_dependency=False)
         if name is None:
             return
-        if not isinstance(name, types.StringTypes):
+        if not isinstance(name, (str,)):
             raise TypeError("Unexpected type: '%s'" % type(name).__name__)
         if name in data:
             raise ConfigureError(
@@ -850,11 +857,11 @@ class ConfigureSandbox(dict):
                 if isinstance(possible_reasons[0], Option):
                     reason = possible_reasons[0]
         if not reason and (isinstance(value, (bool, tuple)) or
-                           isinstance(value, types.StringTypes)):
+                           isinstance(value, (str,))):
             # A reason can be provided automatically when imply_option
             # is called with an immediate value.
             _, filename, line, _, _, _ = inspect.stack()[1]
-            reason = "imply_option at %s:%s" % (filename, line)
+            reason = "imply_option at {}:{}".format(filename, line)
 
         if not reason:
             raise ConfigureError(
@@ -885,10 +892,10 @@ class ConfigureSandbox(dict):
         if not inspect.isfunction(func):
             raise TypeError("Unexpected type: '%s'" % type(func).__name__)
         if func in self._prepared_functions:
-            return func, func.func_globals
+            return func, func.__globals__
 
         glob = SandboxedGlobal(
-            (k, v) for k, v in func.func_globals.iteritems()
+            (k, v) for k, v in func.__globals__.items()
             if (inspect.isfunction(v) and v not in self._templates) or (
                 inspect.isclass(v) and issubclass(v, Exception))
         )
@@ -909,20 +916,20 @@ class ConfigureSandbox(dict):
         # Note this is not entirely bullet proof (if the value is e.g. a list,
         # the list contents could have changed), but covers the bases.
         closure = None
-        if func.func_closure:
+        if func.__closure__:
             def makecell(content):
                 def f():
                     content
-                return f.func_closure[0]
+                return f.__closure__[0]
 
             closure = tuple(makecell(cell.cell_contents)
-                            for cell in func.func_closure)
+                            for cell in func.__closure__)
 
         new_func = wraps(func)(types.FunctionType(
-            func.func_code,
+            func.__code__,
             glob,
             func.__name__,
-            func.func_defaults,
+            func.__defaults__,
             closure
         ))
         @wraps(new_func)
diff --git a/python/mozbuild/mozbuild/configure/check_debug_ranges.py b/python/mozbuild/mozbuild/configure/check_debug_ranges.py
index ca312dff47..5c6e1e9841 100644
--- a/python/mozbuild/mozbuild/configure/check_debug_ranges.py
+++ b/python/mozbuild/mozbuild/configure/check_debug_ranges.py
@@ -6,8 +6,8 @@
 # to a given compilation unit. This is used as a helper to find a bug in some
 # versions of GNU ld.
 
-from __future__ import absolute_import
 
+from __future__ import print_function
 import subprocess
 import sys
 import re
@@ -37,7 +37,7 @@ def get_range_length(range, debug_ranges):
        given offset.'''
     length = 0
     for line in debug_ranges.splitlines():
-        m = re.match('\s*([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)', line)
+        m = re.match(r'\s*([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)', line)
         if m and int(m.group(1), 16) == range:
             length += 1
     return length
@@ -59,4 +59,4 @@ def main(bin, compilation_unit):
 
 
 if __name__ == '__main__':
-    print main(*sys.argv[1:])
+    print((main(*sys.argv[1:])))
diff --git a/python/mozbuild/mozbuild/configure/constants.py b/python/mozbuild/mozbuild/configure/constants.py
index 9e30dd8418..fe41c80d26 100644
--- a/python/mozbuild/mozbuild/configure/constants.py
+++ b/python/mozbuild/mozbuild/configure/constants.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from mozbuild.util import EnumString
 from collections import OrderedDict
@@ -58,7 +57,7 @@ CPU_bitness = {
     'x86_64': 64,
 }
 
-CPU = EnumString.subclass(*CPU_bitness.keys())
+CPU = EnumString.subclass(*list(CPU_bitness.keys()))
 
 Endianness = EnumString.subclass(
     'big',
diff --git a/python/mozbuild/mozbuild/configure/help.py b/python/mozbuild/mozbuild/configure/help.py
index cd7876fbd1..afa0f69c31 100644
--- a/python/mozbuild/mozbuild/configure/help.py
+++ b/python/mozbuild/mozbuild/configure/help.py
@@ -2,13 +2,12 @@
 # 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, print_function, unicode_literals
 
 import os
 from mozbuild.configure.options import Option
 
 
-class HelpFormatter(object):
+class HelpFormatter:
     def __init__(self, argv0):
         self.intro = ['Usage: %s [options]' % os.path.basename(argv0)]
         self.options = ['Options: [defaults in brackets after descriptions]']
@@ -35,7 +34,7 @@ class HelpFormatter(object):
         if len(opt) > 24 or not help:
             target.append('  %s' % opt)
             if help:
-                target.append('%s%s' % (' ' * 28, help))
+                target.append('{}{}'.format(' ' * 28, help))
         else:
             target.append('  %-24s  %s' % (opt, help))
 
diff --git a/python/mozbuild/mozbuild/configure/lint.py b/python/mozbuild/mozbuild/configure/lint.py
index e0a5c8328d..91150c7765 100644
--- a/python/mozbuild/mozbuild/configure/lint.py
+++ b/python/mozbuild/mozbuild/configure/lint.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from StringIO import StringIO
 from . import (
@@ -23,7 +22,7 @@ class LintSandbox(ConfigureSandbox):
         environ = environ or {}
         argv = argv or []
         self._wrapped = {}
-        super(LintSandbox, self).__init__({}, environ=environ, argv=argv,
+        super().__init__({}, environ=environ, argv=argv,
                                           stdout=stdout, stderr=stderr)
 
     def run(self, path=None):
@@ -42,7 +41,7 @@ class LintSandbox(ConfigureSandbox):
             # - don't use @imports
             # - don't have a closure
             # - don't use global variables
-            if func in self._imports or func.func_closure:
+            if func in self._imports or func.__closure__:
                 return True
             for op, arg in disassemble_as_iter(func):
                 if op in ('LOAD_GLOBAL', 'STORE_GLOBAL'):
@@ -68,11 +67,11 @@ class LintSandbox(ConfigureSandbox):
               self._missing_help_dependency(obj)):
             raise ConfigureError("Missing @depends for `%s`: '--help'" %
                                  obj.name)
-        return super(LintSandbox, self)._value_for_depends(
+        return super()._value_for_depends(
             obj, need_help_dependency)
 
     def _prepare_function(self, func):
-        wrapped, glob = super(LintSandbox, self)._prepare_function(func)
+        wrapped, glob = super()._prepare_function(func)
         if wrapped not in self._wrapped:
             self._wrapped[wrapped] = func, glob
         return wrapped, glob
diff --git a/python/mozbuild/mozbuild/configure/lint_util.py b/python/mozbuild/mozbuild/configure/lint_util.py
index f1c2f8731b..dbb6da86ad 100644
--- a/python/mozbuild/mozbuild/configure/lint_util.py
+++ b/python/mozbuild/mozbuild/configure/lint_util.py
@@ -12,9 +12,9 @@ import inspect
 # returns an iterator.
 def disassemble_as_iter(co):
     if inspect.ismethod(co):
-        co = co.im_func
+        co = co.__func__
     if inspect.isfunction(co):
-        co = co.func_code
+        co = co.__code__
     code = co.co_code
     n = len(code)
     i = 0
@@ -30,7 +30,7 @@ def disassemble_as_iter(co):
             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]
diff --git a/python/mozbuild/mozbuild/configure/options.py b/python/mozbuild/mozbuild/configure/options.py
index 4310c8627b..902ce81f40 100644
--- a/python/mozbuild/mozbuild/configure/options.py
+++ b/python/mozbuild/mozbuild/configure/options.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import os
 import sys
@@ -12,7 +11,7 @@ from collections import OrderedDict
 
 def istupleofstrings(obj):
     return isinstance(obj, tuple) and len(obj) and all(
-        isinstance(o, types.StringTypes) for o in obj)
+        isinstance(o, (str,)) for o in obj)
 
 
 class OptionValue(tuple):
@@ -24,7 +23,7 @@ class OptionValue(tuple):
     command line, or default)
     '''
     def __new__(cls, values=(), origin='unknown'):
-        return super(OptionValue, cls).__new__(cls, values)
+        return super().__new__(cls, values)
 
     def __init__(self, values=(), origin='unknown'):
         self.origin = origin
@@ -41,29 +40,32 @@ class OptionValue(tuple):
                     prefix = prefix_set[int(bool(self))]
                     break
             if prefix:
-                option = '--%s-%s' % (prefix, name)
+                option = '--{}-{}'.format(prefix, name)
             elif self:
                 option = '--%s' % name
             else:
                 return ''
             if len(self):
-                return '%s=%s' % (option, ','.join(self))
+                return '{}={}'.format(option, ','.join(self))
             return option
         elif self and not len(self):
             return '%s=1' % option
-        return '%s=%s' % (option, ','.join(self))
+        return '{}={}'.format(option, ','.join(self))
 
     def __eq__(self, other):
         if type(other) != type(self):
             return False
-        return super(OptionValue, self).__eq__(other)
+        return super().__eq__(other)
 
     def __ne__(self, other):
         return not self.__eq__(other)
 
+    # Restore tuple's hash since we define __eq__
+    __hash__ = tuple.__hash__
+
     def __repr__(self):
-        return '%s%s' % (self.__class__.__name__,
-                         super(OptionValue, self).__repr__())
+        return '{}{}'.format(self.__class__.__name__,
+                         super().__repr__())
 
 
 class PositiveOptionValue(OptionValue):
@@ -71,9 +73,11 @@ class PositiveOptionValue(OptionValue):
     in the form of a tuple for when values are given to the option (in the form
     --option=value[,value2...].
     '''
-    def __nonzero__(self):
+    def __bool__(self):
         return True
 
+    __nonzero__ = __bool__
+
 
 class NegativeOptionValue(OptionValue):
     '''Represents the value for a negative option (--disable/--without)
@@ -81,10 +85,10 @@ class NegativeOptionValue(OptionValue):
     This is effectively an empty tuple with a `origin` attribute.
     '''
     def __new__(cls, origin='unknown'):
-        return super(NegativeOptionValue, cls).__new__(cls, origin=origin)
+        return super().__new__(cls, origin=origin)
 
     def __init__(self, origin='unknown'):
-        return super(NegativeOptionValue, self).__init__(origin=origin)
+        return super().__init__(origin=origin)
 
 
 class InvalidOptionError(Exception):
@@ -95,12 +99,12 @@ class ConflictingOptionError(InvalidOptionError):
     def __init__(self, message, **format_data):
         if format_data:
             message = message.format(**format_data)
-        super(ConflictingOptionError, self).__init__(message)
-        for k, v in format_data.iteritems():
+        super().__init__(message)
+        for k, v in format_data.items():
             setattr(self, k, v)
 
 
-class Option(object):
+class Option:
     '''Represents a configure option
 
     A configure option can be a command line flag or an environment variable
@@ -132,7 +136,7 @@ class Option(object):
                 'At least an option name or an environment variable name must '
                 'be given')
         if name:
-            if not isinstance(name, types.StringTypes):
+            if not isinstance(name, (str,)):
                 raise InvalidOptionError('Option must be a string')
             if not name.startswith('--'):
                 raise InvalidOptionError('Option must start with `--`')
@@ -141,7 +145,7 @@ class Option(object):
             if not name.islower():
                 raise InvalidOptionError('Option must be all lowercase')
         if env:
-            if not isinstance(env, types.StringTypes):
+            if not isinstance(env, (str,)):
                 raise InvalidOptionError(
                     'Environment variable name must be a string')
             if not env.isupper():
@@ -151,8 +155,8 @@ class Option(object):
                 isinstance(nargs, int) and nargs >= 0):
             raise InvalidOptionError(
                 "nargs must be a positive integer, '?', '*' or '+'")
-        if (not isinstance(default, types.StringTypes) and
-                not isinstance(default, (bool, types.NoneType)) and
+        if (not isinstance(default, (str,)) and
+                not isinstance(default, (bool, type(None))) and
                 not istupleofstrings(default)):
             raise InvalidOptionError(
                 'default must be a bool, a string or a tuple of strings')
@@ -224,7 +228,7 @@ class Option(object):
                     ', '.join("'%s'" % c for c in choices))
         elif has_choices:
             maxargs = self.maxargs
-            if len(choices) < maxargs and maxargs != sys.maxint:
+            if len(choices) < maxargs and maxargs != sys.maxsize:
                 raise InvalidOptionError('Not enough `choices` for `nargs`')
         self.choices = choices
         self.help = help
@@ -238,7 +242,7 @@ class Option(object):
         where prefix is one of 'with', 'without', 'enable' or 'disable'.
         The '=values' part is optional. Values are separated with commas.
         '''
-        if not isinstance(option, types.StringTypes):
+        if not isinstance(option, (str,)):
             raise InvalidOptionError('Option must be a string')
 
         elements = option.split('=', 1)
@@ -271,7 +275,7 @@ class Option(object):
             assert not prefix
             return name
         elif prefix:
-            return '--%s-%s' % (prefix, name)
+            return '--{}-{}'.format(prefix, name)
         return '--%s' % name
 
     @property
@@ -291,7 +295,7 @@ class Option(object):
     def maxargs(self):
         if isinstance(self.nargs, int):
             return self.nargs
-        return 1 if self.nargs == '?' else sys.maxint
+        return 1 if self.nargs == '?' else sys.maxsize
 
     def _validate_nargs(self, num):
         minargs, maxargs = self.minargs, self.maxargs
@@ -331,7 +335,7 @@ class Option(object):
         values = PositiveOptionValue(values, origin=origin)
 
         if not self._validate_nargs(len(values)):
-            raise InvalidOptionError('%s takes %s value%s' % (
+            raise InvalidOptionError('{} takes {} value{}'.format(
                 option,
                 {
                     '?': '0 or 1',
@@ -371,11 +375,11 @@ class Option(object):
         return values
 
     def __repr__(self):
-        return '<%s.%s [%s]>' % (self.__class__.__module__,
+        return '<{}.{} [{}]>'.format(self.__class__.__module__,
                                  self.__class__.__name__, self.option)
 
 
-class CommandLineHelper(object):
+class CommandLineHelper:
     '''Helper class to handle the various ways options can be given either
     on the command line of through the environment.
 
@@ -441,7 +445,7 @@ class CommandLineHelper(object):
         elif option.env and args is self._args:
             env = self._environ.get(option.env)
             if env is not None:
-                arg = '%s=%s' % (option.env, env)
+                arg = '{}={}'.format(option.env, env)
                 origin = 'environment'
 
         origin = self._origins.get(arg, origin)
@@ -481,5 +485,5 @@ class CommandLineHelper(object):
 
     def __iter__(self):
         for d in (self._args, self._extra_args):
-            for arg, pos in d.itervalues():
+            for arg, pos in list(d.values()):
                 yield arg
diff --git a/python/mozbuild/mozbuild/configure/util.py b/python/mozbuild/mozbuild/configure/util.py
index c7a305282b..c7bc64e575 100644
--- a/python/mozbuild/mozbuild/configure/util.py
+++ b/python/mozbuild/mozbuild/configure/util.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import codecs
 import itertools
@@ -12,7 +11,27 @@ import os
 import sys
 from collections import deque
 from contextlib import contextmanager
-from distutils.version import LooseVersion
+import re
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0
 
 def getpreferredencoding():
     # locale._parse_localename makes locale.getpreferredencoding
@@ -52,7 +71,7 @@ class Version(LooseVersion):
 
     def __cmp__(self, other):
         # LooseVersion checks isinstance(StringType), so work around it.
-        if isinstance(other, unicode):
+        if isinstance(other, str):
             other = other.encode('ascii')
         return LooseVersion.__cmp__(self, other)
 
@@ -73,20 +92,13 @@ class ConfigureOutputHandler(logging.Handler):
     manager.
     '''
     def __init__(self, stdout=sys.stdout, stderr=sys.stderr, maxlen=20):
-        super(ConfigureOutputHandler, self).__init__()
+        super().__init__()
 
         # Python has this feature where it sets the encoding of pipes to
         # ascii, which blatantly fails when trying to print out non-ascii.
         def fix_encoding(fh):
-            try:
-                isatty = fh.isatty()
-            except AttributeError:
-                isatty = True
-
-            if not isatty:
-                encoding = getpreferredencoding()
-                if encoding:
-                    return codecs.getwriter(encoding)(fh)
+            # In Python 3, text streams handle encoding natively.
+            # Just return the stream as-is.
             return fh
 
         self._stdout = fix_encoding(stdout)
@@ -190,7 +202,7 @@ class ConfigureOutputHandler(logging.Handler):
         self._keep_if_debug = self.KEEP
 
 
-class LineIO(object):
+class LineIO:
     '''File-like class that sends each line of the written data to a callback
     (without carriage returns).
     '''
@@ -200,8 +212,8 @@ class LineIO(object):
         self._encoding = getpreferredencoding()
 
     def write(self, buf):
-        if self._encoding and isinstance(buf, str):
-            buf = buf.decode(self._encoding)
+        if isinstance(buf, bytes):
+            buf = buf.decode(self._encoding or 'utf-8', errors='replace')
         lines = buf.splitlines()
         if not lines:
             return
diff --git a/python/mozbuild/mozbuild/controller/building.py b/python/mozbuild/mozbuild/controller/building.py
index 663f789b8e..4d59d216f2 100644
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -2,8 +2,8 @@
 # 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, unicode_literals
 
+from __future__ import print_function
 import getpass
 import json
 import logging
@@ -62,7 +62,7 @@ BuildOutputResult = namedtuple('BuildOutputResult',
     ('warning', 'state_changed', 'for_display'))
 
 
-class TierStatus(object):
+class TierStatus:
     """Represents the state and progress of tier traversal.
 
     The build system is organized into linear phases called tiers. Each tier
@@ -470,7 +470,7 @@ class BuildMonitor(MozbuildObject):
         return ccache_stats
 
 
-class CCacheStats(object):
+class CCacheStats:
     """Holds statistics from ccache.
 
     Instances can be subtracted from each other to obtain differences.
@@ -625,7 +625,7 @@ class CCacheStats(object):
         lines = []
 
         if self.cache_dir:
-            lines.append('%s%s' % (self.DIRECTORY_DESCRIPTION.ljust(LEFT_ALIGN),
+            lines.append('{}{}'.format(self.DIRECTORY_DESCRIPTION.ljust(LEFT_ALIGN),
                                    self.cache_dir))
 
         for stat_key, stat_description in self.STATS_KEYS:
@@ -639,7 +639,7 @@ class CCacheStats(object):
             else:
                 value = '%8u' % value
 
-            lines.append('%s%s' % (stat_description.ljust(LEFT_ALIGN), value))
+            lines.append('{}{}'.format(stat_description.ljust(LEFT_ALIGN), value))
 
         return '\n'.join(lines)
 
@@ -666,8 +666,8 @@ class BuildDriver(MozbuildObject):
         """Install test files."""
 
         if self.is_clobber_needed():
-            print(INSTALL_TESTS_CLOBBER.format(
-                  clobber_file=os.path.join(self.topobjdir, 'CLOBBER')))
+            print((INSTALL_TESTS_CLOBBER.format(
+                  clobber_file=os.path.join(self.topobjdir, 'CLOBBER'))))
             sys.exit(1)
 
         if not test_objs:
diff --git a/python/mozbuild/mozbuild/controller/clobber.py b/python/mozbuild/mozbuild/controller/clobber.py
index ba83e24285..a3f0ea5700 100644
--- a/python/mozbuild/mozbuild/controller/clobber.py
+++ b/python/mozbuild/mozbuild/controller/clobber.py
@@ -2,7 +2,6 @@
 # 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, print_function
 
 r'''This module contains code for managing clobbering of the tree.'''
 
@@ -39,7 +38,7 @@ Well, are ya? -- you can ignore this clobber requirement by running:
  $ touch {clobber_file}
 '''.splitlines()])
 
-class Clobberer(object):
+class Clobberer:
     def __init__(self, topsrcdir, topobjdir):
         """Create a new object to manage clobbering the tree.
 
@@ -86,7 +85,7 @@ class Clobberer(object):
         This returns a list of lines describing why the clobber was required.
         Each line is stripped of leading and trailing whitespace.
         """
-        with open(self.src_clobber, 'rt') as fh:
+        with open(self.src_clobber) as fh:
             lines = [l.strip() for l in fh.readlines()]
             return [l for l in lines if l and not l.startswith('#')]
 
@@ -114,14 +113,13 @@ class Clobberer(object):
         }
 
         if full:
-            # mozfile doesn't like unicode arguments (bug 818783).
-            paths = [self.topobjdir.encode('utf-8')]
+            paths = [self.topobjdir]
         else:
             try:
                 paths = []
                 for p in os.listdir(self.topobjdir):
                     if p not in no_clobber:
-                        paths.append(os.path.join(self.topobjdir, p).encode('utf-8'))
+                        paths.append(os.path.join(self.topobjdir, p))
             except OSError as e:
                 if e.errno != errno.ENOENT:
                     raise
@@ -200,7 +198,7 @@ class Clobberer(object):
             self.ensure_objdir_state()
             print('Successfully completed auto clobber.', file=fh)
             return True, True, None
-        except (IOError) as error:
+        except (OSError) as error:
             return True, False, self._message(
                 'Error when automatically clobbering: ' + str(error))
 
diff --git a/python/mozbuild/mozbuild/doctor.py b/python/mozbuild/mozbuild/doctor.py
index 2175042bfa..37c9786500 100644
--- a/python/mozbuild/mozbuild/doctor.py
+++ b/python/mozbuild/mozbuild/doctor.py
@@ -2,8 +2,8 @@
 # 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
 
+from __future__ import print_function
 import os
 import subprocess
 import sys
@@ -11,7 +11,27 @@ import sys
 import psutil
 
 from distutils.util import strtobool
-from distutils.version import LooseVersion
+import re
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0
 import mozpack.path as mozpath
 
 # Minimum recommended logical processors in system.
@@ -83,7 +103,7 @@ class Doctor(object):
         valid = False
         while not valid and limit > 0:
             try:
-                choice = strtobool(raw_input(prompt + '[Y/N]\n'))
+                choice = strtobool(input(prompt + '[Y/N]\n'))
                 valid = True
             except ValueError:
                 print("ERROR! Please enter a valid option!")
@@ -103,11 +123,11 @@ class Doctor(object):
             if status == 'SKIPPED':
                 continue
             self.results.append(result)
-            print('%s...\t%s\n' % (
+            print(('%s...\t%s\n' % (
                    result.get('desc', ''),
                    status
                 )
-            ).expandtabs(40)
+            ).expandtabs(40))
 
     @property
     def platform(self):
@@ -212,7 +232,7 @@ class Doctor(object):
                         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'
diff --git a/python/mozbuild/mozbuild/dotproperties.py b/python/mozbuild/mozbuild/dotproperties.py
index 972ff23299..b2d8d19ed8 100644
--- a/python/mozbuild/mozbuild/dotproperties.py
+++ b/python/mozbuild/mozbuild/dotproperties.py
@@ -5,16 +5,12 @@
 # This file contains utility functions for reading .properties files, like
 # region.properties.
 
-from __future__ import absolute_import, unicode_literals
 
 import codecs
 import re
 import sys
 
-if sys.version_info[0] == 3:
-    str_type = str
-else:
-    str_type = basestring
+str_type = str
 
 class DotProperties:
     r'''A thin representation of a key=value .properties file.'''
@@ -38,7 +34,7 @@ class DotProperties:
             line = l.strip()
             if not line or line.startswith('#'):
                 continue
-            (k, v) = re.split('\s*=\s*', line, 1)
+            (k, v) = re.split(r'\s*=\s*', line, 1)
             self._properties[k] = v
 
     def get(self, key, default=None):
@@ -52,7 +48,7 @@ class DotProperties:
         if not prefix.endswith('.'):
             prefix = prefix + '.'
         indexes = []
-        for k, v in self._properties.iteritems():
+        for k, v in self._properties.items():
             if not k.startswith(prefix):
                 continue
             key = k[len(prefix):]
@@ -73,8 +69,8 @@ class DotProperties:
         if not prefix.endswith('.'):
             prefix = prefix + '.'
 
-        D = dict((k[len(prefix):], v) for k, v in self._properties.iteritems()
-                 if k.startswith(prefix) and '.' not in k[len(prefix):])
+        D = {k[len(prefix):]: v for k, v in self._properties.items()
+                 if k.startswith(prefix) and '.' not in k[len(prefix):]}
 
         for required_key in required_keys:
             if not required_key in D:
diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py
index 46f6d12cb5..711101d601 100644
--- a/python/mozbuild/mozbuild/frontend/context.py
+++ b/python/mozbuild/mozbuild/frontend/context.py
@@ -14,7 +14,6 @@ If you are looking for the absolute authority on what moz.build files can
 contain, you've come to the right place.
 """
 
-from __future__ import absolute_import, unicode_literals
 
 import os
 
@@ -50,7 +49,7 @@ from types import FunctionType
 import itertools
 
 
-class ContextDerivedValue(object):
+class ContextDerivedValue:
     """Classes deriving from this one receive a special treatment in a
     Context. See Context documentation.
     """
@@ -234,10 +233,10 @@ class Context(KeyedDefaultDict):
         This function is transactional: if setitem fails for one of the values,
         the context is not updated at all."""
         if isinstance(iterable, dict):
-            iterable = iterable.items()
+            iterable = list(iterable.items())
 
         update = {}
-        for key, value in itertools.chain(iterable, kwargs.items()):
+        for key, value in itertools.chain(iterable, list(kwargs.items())):
             stored_type = self._validate(key, value)
             # Don't create an instance of stored_type if coercion is needed,
             # until all values are validated.
@@ -253,7 +252,7 @@ class Context(KeyedDefaultDict):
 class TemplateContext(Context):
     def __init__(self, template=None, allowed_variables={}, config=None):
         self.template = template
-        super(TemplateContext, self).__init__(allowed_variables, config)
+        super().__init__(allowed_variables, config)
 
     def _validate(self, key, value):
         return Context._validate(self, key, value, True)
@@ -297,7 +296,7 @@ class InitializedDefines(ContextDerivedValue, OrderedDict):
             self.update(value)
 
 
-class FinalTargetValue(ContextDerivedValue, unicode):
+class FinalTargetValue(ContextDerivedValue, str):
     def __new__(cls, context, value=""):
         if not value:
             value = 'dist/'
@@ -307,14 +306,14 @@ class FinalTargetValue(ContextDerivedValue, unicode):
                 value += 'bin'
             if context['DIST_SUBDIR']:
                 value += '/' + context['DIST_SUBDIR']
-        return unicode.__new__(cls, value)
+        return str.__new__(cls, value)
 
 
 def Enum(*values):
     assert len(values)
     default = values[0]
 
-    class EnumClass(object):
+    class EnumClass:
         def __new__(cls, value=None):
             if value is None:
                 return default
@@ -353,9 +352,9 @@ class PathMeta(type):
                 cls = AbsolutePath
             else:
                 cls = SourcePath
-        return super(PathMeta, cls).__call__(context, value)
+        return super().__call__(context, value)
 
-class Path(ContextDerivedValue, unicode):
+class Path(ContextDerivedValue, str, metaclass=PathMeta):
     """Stores and resolves a source path relative to a given context
 
     This class is used as a backing type for some of the sandbox variables.
@@ -366,10 +365,9 @@ class Path(ContextDerivedValue, unicode):
       - '!objdir/relative/paths'
       - '%/filesystem/absolute/paths'
     """
-    __metaclass__ = PathMeta
 
     def __new__(cls, context, value=None):
-        return super(Path, cls).__new__(cls, value)
+        return super().__new__(cls, value)
 
     def __init__(self, context, value=None):
         # Only subclasses should be instantiated.
@@ -384,9 +382,11 @@ class Path(ContextDerivedValue, unicode):
         return Path(self.context, mozpath.join(self, *p))
 
     def __cmp__(self, other):
+        def _cmp(a, b):
+            return (a > b) - (a < b)
         if isinstance(other, Path) and self.srcdir != other.srcdir:
-            return cmp(self.full_path, other.full_path)
-        return cmp(unicode(self), other)
+            return _cmp(self.full_path, other.full_path)
+        return _cmp(str(self), other)
 
     # __cmp__ is not enough because unicode has __eq__, __ne__, etc. defined
     # and __cmp__ is only used for those when they don't exist.
@@ -409,7 +409,7 @@ class Path(ContextDerivedValue, unicode):
         return self.__cmp__(other) >= 0
 
     def __repr__(self):
-        return '<%s (%s)%s>' % (self.__class__.__name__, self.srcdir, self)
+        return '<{} ({}){}>'.format(self.__class__.__name__, self.srcdir, self)
 
     def __hash__(self):
         return hash(self.full_path)
@@ -426,7 +426,7 @@ class SourcePath(Path):
             raise ValueError('Object directory paths are not allowed')
         if value.startswith('%'):
             raise ValueError('Filesystem absolute paths are not allowed')
-        super(SourcePath, self).__init__(context, value)
+        super().__init__(context, value)
 
         if value.startswith('/'):
             path = None
@@ -464,7 +464,7 @@ class RenamedSourcePath(SourcePath):
     def __init__(self, context, value):
         assert isinstance(value, tuple)
         source, self._target_basename = value
-        super(RenamedSourcePath, self).__init__(context, source)
+        super().__init__(context, source)
 
     @property
     def target_basename(self):
@@ -476,7 +476,7 @@ class ObjDirPath(Path):
     def __init__(self, context, value=None):
         if not value.startswith('!'):
             raise ValueError('Object directory paths must start with ! prefix')
-        super(ObjDirPath, self).__init__(context, value)
+        super().__init__(context, value)
 
         if value.startswith('!/'):
             path = mozpath.join(context.config.topobjdir,value[2:])
@@ -492,7 +492,7 @@ class AbsolutePath(Path):
             raise ValueError('Absolute paths must start with % prefix')
         if not os.path.isabs(value[1:]):
             raise ValueError('Path \'%s\' is not absolute' % value[1:])
-        super(AbsolutePath, self).__init__(context, value)
+        super().__init__(context, value)
 
         self.full_path = mozpath.normpath(value[1:])
 
@@ -505,7 +505,7 @@ def ContextDerivedTypedList(klass, base_class=List):
     class _TypedList(ContextDerivedValue, TypedList(klass, base_class)):
         def __init__(self, context, iterable=[]):
             self.context = context
-            super(_TypedList, self).__init__(iterable)
+            super().__init__(iterable)
 
         def normalize(self, e):
             if not isinstance(e, klass):
@@ -521,7 +521,7 @@ def ContextDerivedTypedListWithItems(type, base_class=List):
     class _TypedListWithItems(ContextDerivedTypedList(type, base_class)):
         def __getitem__(self, name):
             name = self.normalize(name)
-            return super(_TypedListWithItems, self).__getitem__(name)
+            return super().__getitem__(name)
 
     return _TypedListWithItems
 
@@ -594,7 +594,7 @@ def OrderedListWithAction(action):
         def __init__(self, context, *args):
             def _action(item):
                 return item, action(context, item)
-            super(_OrderedListWithAction, self).__init__(action=_action, *args)
+            super().__init__(action=_action, *args)
 
     return _OrderedListWithAction
 
@@ -610,12 +610,12 @@ def TypedListWithAction(typ, action):
         def __init__(self, context, *args):
             def _action(item):
                 return item, action(context, item)
-            super(_TypedListWithAction, self).__init__(action=_action, *args)
+            super().__init__(action=_action, *args)
     return _TypedListWithAction
 
 WebPlatformTestManifest = TypedNamedTuple("WebPlatformTestManifest",
-                                          [("manifest_path", unicode),
-                                           ("test_root", unicode)])
+                                          [("manifest_path", str),
+                                           ("test_root", str)])
 ManifestparserManifestList = OrderedListWithAction(read_manifestparser_manifest)
 ReftestManifestList = OrderedListWithAction(read_reftest_manifest)
 WptManifestList = TypedListWithAction(WebPlatformTestManifest, read_wpt_manifest)
@@ -623,12 +623,12 @@ WptManifestList = TypedListWithAction(WebPlatformTestManifest, read_wpt_manifest
 OrderedSourceList = ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList)
 OrderedTestFlavorList = TypedList(Enum(*all_test_flavors()),
                                   StrictOrderingOnAppendList)
-OrderedStringList = TypedList(unicode, StrictOrderingOnAppendList)
+OrderedStringList = TypedList(str, StrictOrderingOnAppendList)
 DependentTestsEntry = ContextDerivedTypedRecord(('files', OrderedSourceList),
                                                 ('tags', OrderedStringList),
                                                 ('flavors', OrderedTestFlavorList))
 BugzillaComponent = TypedNamedTuple('BugzillaComponent',
-                        [('product', unicode), ('component', unicode)])
+                        [('product', str), ('component', str)])
 
 
 class Files(SubContext):
@@ -750,7 +750,7 @@ class Files(SubContext):
     }
 
     def __init__(self, parent, pattern=None):
-        super(Files, self).__init__(parent)
+        super().__init__(parent)
         self.pattern = pattern
         self.finalized = set()
         self.test_files = set()
@@ -766,8 +766,8 @@ class Files(SubContext):
 
         for k, v in other.items():
             if k == 'IMPACTED_TESTS':
-                self.test_files |= set(mozpath.relpath(e.full_path, e.context.config.topsrcdir)
-                                       for e in v.files)
+                self.test_files |= {mozpath.relpath(e.full_path, e.context.config.topsrcdir)
+                                       for e in v.files}
                 self.test_tags |= set(v.tags)
                 self.test_flavors |= set(v.flavors)
                 continue
@@ -909,7 +909,7 @@ VARIABLES = {
         """),
 
     'GENERATED_FILES': (StrictOrderingOnAppendListWithFlagsFactory({
-                'script': unicode,
+                'script': str,
                 'inputs': list }), list,
         """Generic generated files.
 
@@ -1054,7 +1054,7 @@ VARIABLES = {
         """Like ``OBJDIR_FILES``, with preprocessing. Use sparingly.
         """),
 
-    'FINAL_LIBRARY': (unicode, unicode,
+    'FINAL_LIBRARY': (str, str,
         """Library in which the objects of the current directory will be linked.
 
         This variable contains the name of a library, defined elsewhere with
@@ -1105,7 +1105,7 @@ VARIABLES = {
         """A list of python unit tests.
         """),
 
-    'HOST_LIBRARY_NAME': (unicode, unicode,
+    'HOST_LIBRARY_NAME': (str, str,
         """Name of target library generated when cross compiling.
         """),
 
@@ -1123,7 +1123,7 @@ VARIABLES = {
         libraries that link into this library via FINAL_LIBRARY.
         """),
 
-    'LIBRARY_NAME': (unicode, unicode,
+    'LIBRARY_NAME': (str, str,
         """The code name of the library generated for a directory.
 
         By default STATIC_LIBRARY_NAME and SHARED_LIBRARY_NAME take this name.
@@ -1135,7 +1135,7 @@ VARIABLES = {
         ``example/components/xpcomsample.lib`` on Windows.
         """),
 
-    'SHARED_LIBRARY_NAME': (unicode, unicode,
+    'SHARED_LIBRARY_NAME': (str, str,
         """The name of the static library generated for a directory, if it needs to
         differ from the library code name.
 
@@ -1149,7 +1149,7 @@ VARIABLES = {
         Implies FORCE_SHARED_LIB.
         """),
 
-    'STATIC_LIBRARY_NAME': (unicode, unicode,
+    'STATIC_LIBRARY_NAME': (str, str,
         """The name of the static library generated for a directory, if it needs to
         differ from the library code name.
 
@@ -1185,37 +1185,37 @@ VARIABLES = {
 
         This variable contains a list of system libaries to link against.
         """),
-    'RCFILE': (unicode, unicode,
+    'RCFILE': (str, str,
         """The program .rc file.
 
         This variable can only be used on Windows.
         """),
 
-    'RESFILE': (unicode, unicode,
+    'RESFILE': (str, str,
         """The program .res file.
 
         This variable can only be used on Windows.
         """),
 
-    'RCINCLUDE': (unicode, unicode,
+    'RCINCLUDE': (str, str,
         """The resource script file to be included in the default .res file.
 
         This variable can only be used on Windows.
         """),
 
-    'DEFFILE': (unicode, unicode,
+    'DEFFILE': (str, str,
         """The program .def (module definition) file.
 
         This variable can only be used on Windows.
         """),
 
-    'LD_VERSION_SCRIPT': (unicode, unicode,
+    'LD_VERSION_SCRIPT': (str, str,
         """The linker version script for shared libraries.
 
         This variable can only be used on Linux.
         """),
 
-    'SYMBOLS_FILE': (Path, unicode,
+    'SYMBOLS_FILE': (Path, str,
         """A file containing a list of symbols to export from a shared library.
 
         The given file contains a list of symbols to be exported, and is
@@ -1270,7 +1270,7 @@ VARIABLES = {
         ``BIN_SUFFIX``, the name will remain unchanged.
         """),
 
-    'SONAME': (unicode, unicode,
+    'SONAME': (str, str,
         """The soname of the shared object currently being linked
 
         soname is the "logical name" of a shared object, often used to provide
@@ -1326,7 +1326,7 @@ VARIABLES = {
         ``GENERATED_FILES``.
         """),
 
-    'PROGRAM' : (unicode, unicode,
+    'PROGRAM' : (str, str,
         """Compiled executable name.
 
         If the configuration token ``BIN_SUFFIX`` is set, its value will be
@@ -1334,7 +1334,7 @@ VARIABLES = {
         ``BIN_SUFFIX``, ``PROGRAM`` will remain unchanged.
         """),
 
-    'HOST_PROGRAM' : (unicode, unicode,
+    'HOST_PROGRAM' : (str, str,
         """Compiled host executable name.
 
         If the configuration token ``HOST_BIN_SUFFIX`` is set, its value will be
@@ -1372,7 +1372,7 @@ VARIABLES = {
         files.
         """),
 
-    'XPIDL_MODULE': (unicode, unicode,
+    'XPIDL_MODULE': (str, str,
         """XPCOM Interface Definition Module Name.
 
         This is the name of the ``.xpt`` file that is created by linking
@@ -1441,7 +1441,7 @@ VARIABLES = {
          """),
 
     'WEBIDL_EXAMPLE_INTERFACES': (StrictOrderingOnAppendList, list,
-        """Names of example WebIDL interfaces to build as part of the build.
+        r"""Names of example WebIDL interfaces to build as part of the build.
 
         Names in this list correspond to WebIDL interface names defined in
         WebIDL files included in the build from one of the \*WEBIDL_FILES
@@ -1526,14 +1526,14 @@ VARIABLES = {
         """),
 
     # The following variables are used to control the target of installed files.
-    'XPI_NAME': (unicode, unicode,
+    'XPI_NAME': (str, str,
         """The name of an extension XPI to generate.
 
         When this variable is present, the results of this directory will end up
         being packaged into an extension instead of the main dist/bin results.
         """),
 
-    'DIST_SUBDIR': (unicode, unicode,
+    'DIST_SUBDIR': (str, str,
         """The name of an alternate directory to install files to.
 
         When this variable is present, the results of this directory will end up
@@ -1541,7 +1541,7 @@ VARIABLES = {
         otherwise be placed.
         """),
 
-    'FINAL_TARGET': (FinalTargetValue, unicode,
+    'FINAL_TARGET': (FinalTargetValue, str,
         """The name of the directory to install targets to.
 
         The directory is relative to the top of the object directory. The
@@ -1572,7 +1572,7 @@ VARIABLES = {
 
     'GYP_DIRS': (StrictOrderingOnAppendListWithFlagsFactory({
             'variables': dict,
-            'input': unicode,
+            'input': str,
             'sandbox_vars': dict,
             'no_chromium': bool,
             'no_unified': bool,
diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py
index c6ed4f65ef..1ceaff3b81 100644
--- a/python/mozbuild/mozbuild/frontend/data.py
+++ b/python/mozbuild/mozbuild/frontend/data.py
@@ -15,7 +15,6 @@ contains the code for converting executed mozbuild files into these data
 structures.
 """
 
-from __future__ import absolute_import, unicode_literals
 
 from mozbuild.util import StrictOrderingOnAppendList
 from mozpack.chrome.manifest import ManifestEntry
@@ -32,7 +31,7 @@ from ..testing import (
 )
 
 
-class TreeMetadata(object):
+class TreeMetadata:
     """Base class for all data being captured."""
     __slots__ = ()
 
@@ -92,7 +91,7 @@ class ContextDerived(TreeMetadata):
         return mozpath.relpath(self.objdir, self.topobjdir)
 
 
-class HostMixin(object):
+class HostMixin:
     @property
     def defines(self):
         defines = self._context['HOST_DEFINES']
@@ -186,13 +185,13 @@ class BaseDefines(ContextDerived):
         self.defines = defines
 
     def get_defines(self):
-        for define, value in self.defines.iteritems():
+        for define, value in self.defines.items():
             if value is True:
                 yield('-D%s' % define)
             elif value is False:
                 yield('-U%s' % define)
             else:
-                yield('-D%s=%s' % (define, value))
+                yield('-D{}={}'.format(define, value))
 
     def update(self, more_defines):
         if isinstance(more_defines, Defines):
@@ -344,7 +343,7 @@ class Linkable(ContextDerived):
             raise LinkageWrongKindError(
                 'Linkable.link_library() does not take components.')
         if obj.KIND != self.KIND:
-            raise LinkageWrongKindError('%s != %s' % (obj.KIND, self.KIND))
+            raise LinkageWrongKindError('{} != {}'.format(obj.KIND, self.KIND))
         self.linked_libraries.append(obj)
         if obj.cxx_link:
             self.cxx_link = True
@@ -357,7 +356,7 @@ class Linkable(ContextDerived):
             if self.config.substs.get('GNU_CC'):
                 lib = '-l%s' % lib
             else:
-                lib = '%s%s%s' % (
+                lib = '{}{}{}'.format(
                     self.config.import_prefix,
                     lib,
                     self.config.import_suffix,
@@ -393,7 +392,7 @@ class BaseProgram(Linkable):
         self.is_unit_test = is_unit_test
 
     def __repr__(self):
-        return '<%s: %s/%s>' % (type(self).__name__, self.relobjdir, self.program)
+        return '<{}: {}/{}>'.format(type(self).__name__, self.relobjdir, self.program)
 
 
 class Program(BaseProgram):
@@ -435,7 +434,7 @@ class BaseLibrary(Linkable):
 
         self.basename = self.lib_name = basename
         if self.lib_name:
-            self.lib_name = '%s%s%s' % (
+            self.lib_name = '{}{}{}'.format(
                 context.config.lib_prefix,
                 self.lib_name,
                 context.config.lib_suffix
@@ -445,7 +444,7 @@ class BaseLibrary(Linkable):
         self.refs = []
 
     def __repr__(self):
-        return '<%s: %s/%s>' % (type(self).__name__, self.relobjdir, self.lib_name)
+        return '<{}: {}/{}>'.format(type(self).__name__, self.relobjdir, self.lib_name)
 
 
 class Library(BaseLibrary):
@@ -507,18 +506,18 @@ class SharedLibrary(Library):
         if variant == self.FRAMEWORK:
             self.import_name = self.lib_name
         else:
-            self.import_name = '%s%s%s' % (
+            self.import_name = '{}{}{}'.format(
                 context.config.import_prefix,
                 self.lib_name,
                 context.config.import_suffix,
             )
-            self.lib_name = '%s%s%s' % (
+            self.lib_name = '{}{}{}'.format(
                 context.config.dll_prefix,
                 self.lib_name,
                 context.config.dll_suffix,
             )
         if soname:
-            self.soname = '%s%s%s' % (
+            self.soname = '{}{}{}'.format(
                 context.config.dll_prefix,
                 soname,
                 context.config.dll_suffix,
@@ -541,7 +540,7 @@ class SharedLibrary(Library):
 
 
 
-class ExternalLibrary(object):
+class ExternalLibrary:
     """Empty mixin for libraries built by an external build system."""
 
 
@@ -695,7 +694,7 @@ class ContextWrapped(ContextDerived):
         self.wrapped = wrapped
 
 
-class JavaJarData(object):
+class JavaJarData:
     """Represents a Java JAR file.
 
     A Java JAR has the following members:
@@ -786,7 +785,7 @@ class UnifiedSources(BaseSources):
             unified_prefix = unified_prefix.replace('/', '_')
 
             suffix = self.canonical_suffix[1:]
-            unified_prefix='Unified_%s_%s' % (suffix, unified_prefix)
+            unified_prefix='Unified_{}_{}'.format(suffix, unified_prefix)
             self.unified_source_mapping = list(group_unified_files(source_files,
                                                                    unified_prefix=unified_prefix,
                                                                    unified_suffix=suffix,
diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py
index faa41786ac..58f907469f 100644
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import itertools
 import logging
@@ -117,7 +116,7 @@ class TreeMetadataEmitter(LoggingMixin):
         # rid ourselves of 2.6.
         self.info = {}
         for k, v in mozinfo.info.items():
-            if isinstance(k, unicode):
+            if isinstance(k, str):
                 k = k.encode('ascii')
             self.info[k] = v
 
@@ -135,7 +134,7 @@ class TreeMetadataEmitter(LoggingMixin):
         paths = []
         if os.path.exists(subconfigures):
             paths = open(subconfigures).read().splitlines()
-        self._external_paths = set(mozpath.normsep(d) for d in paths)
+        self._external_paths = {mozpath.normsep(d) for d in paths}
         self._emitter_time = 0.0
         self._object_count = 0
         self._test_files_converter = SupportFilesConverter()
@@ -175,7 +174,7 @@ class TreeMetadataEmitter(LoggingMixin):
                 objs = list(self.emit_from_context(out))
                 self._emitter_time += time.time() - start
 
-                for o in emit_objs(objs): yield o
+                yield from emit_objs(objs)
 
             else:
                 raise Exception('Unhandled output type: %s' % type(out))
@@ -186,7 +185,7 @@ class TreeMetadataEmitter(LoggingMixin):
             objs = list(self._emit_libs_derived(contexts))
             self._emitter_time += time.time() - start
 
-            for o in emit_objs(objs): yield o
+            yield from emit_objs(objs)
 
     def _emit_libs_derived(self, contexts):
         # First do FINAL_LIBRARY linkage.
@@ -204,8 +203,8 @@ class TreeMetadataEmitter(LoggingMixin):
             # have the library linked. The typical usecase is when building
             # both a static and a shared library in a directory, and having
             # that as a FINAL_LIBRARY.
-            if len(set(type(l) for l in candidates)) == len(candidates) and \
-                   len(set(l.objdir for l in candidates)) == 1:
+            if len({type(l) for l in candidates}) == len(candidates) and \
+                   len({l.objdir for l in candidates}) == 1:
                 for c in candidates:
                     c.link_library(lib)
             else:
@@ -223,8 +222,7 @@ class TreeMetadataEmitter(LoggingMixin):
             for o in lib.refs:
                 yield o
                 if isinstance(o, StaticLibrary):
-                    for q in recurse_refs(o):
-                        yield q
+                    yield from recurse_refs(o)
 
         # Check that all static libraries refering shared libraries in
         # USE_LIBS are linked into a shared library or program.
@@ -314,7 +312,7 @@ class TreeMetadataEmitter(LoggingMixin):
                             libs[key] = l
                         if key not in libs:
                             libs[key] = l
-                candidates = libs.values()
+                candidates = list(libs.values())
                 if force_static and not candidates:
                     if dir:
                         raise SandboxValidationError(
@@ -371,34 +369,34 @@ class TreeMetadataEmitter(LoggingMixin):
 
     def _parse_cargo_file(self, toml_file):
         """Parse toml_file and return a Python object representation of it."""
-        with open(toml_file, 'r') as f:
+        with open(toml_file) as f:
             return pytoml.load(f)
 
     def _verify_deps(self, context, crate_dir, crate_name, dependencies, description='Dependency'):
         """Verify that a crate's dependencies all specify local paths."""
-        for dep_crate_name, values in dependencies.iteritems():
+        for dep_crate_name, values in dependencies.items():
             # A simple version number.
-            if isinstance(values, (str, unicode)):
+            if isinstance(values, (str, str)):
                 raise SandboxValidationError(
-                    '%s %s of crate %s does not list a path' % (description, dep_crate_name, crate_name),
+                    '{} {} of crate {} does not list a path'.format(description, dep_crate_name, crate_name),
                     context)
 
             dep_path = values.get('path', None)
             if not dep_path:
                 raise SandboxValidationError(
-                    '%s %s of crate %s does not list a path' % (description, dep_crate_name, crate_name),
+                    '{} {} of crate {} does not list a path'.format(description, dep_crate_name, crate_name),
                     context)
 
             # Try to catch the case where somebody listed a
             # local path for development.
             if os.path.isabs(dep_path):
                 raise SandboxValidationError(
-                    '%s %s of crate %s has a non-relative path' % (description, dep_crate_name, crate_name),
+                    '{} {} of crate {} has a non-relative path'.format(description, dep_crate_name, crate_name),
                     context)
 
             if not os.path.exists(mozpath.join(context.config.topsrcdir, crate_dir, dep_path)):
                 raise SandboxValidationError(
-                    '%s %s of crate %s refers to a non-existent path' % (description, dep_crate_name, crate_name),
+                    '{} {} of crate {} refers to a non-existent path'.format(description, dep_crate_name, crate_name),
                     context)
 
     def _handle_linkables(self, context, passthru, generated_files):
@@ -667,7 +665,7 @@ class TreeMetadataEmitter(LoggingMixin):
         assert not gen_sources['UNIFIED_SOURCES']
 
         no_pgo = context.get('NO_PGO')
-        no_pgo_sources = [f for f, flags in all_flags.iteritems()
+        no_pgo_sources = [f for f, flags in all_flags.items()
                           if flags.no_pgo]
         if no_pgo:
             if no_pgo_sources:
@@ -684,17 +682,17 @@ class TreeMetadataEmitter(LoggingMixin):
         # in the definition; we'll add it in programmatically after defining
         # things.
         suffix_map = {
-            '.s': set(['.asm']),
+            '.s': {'.asm'},
             '.c': set(),
             '.m': set(),
             '.mm': set(),
-            '.cpp': set(['.cc', '.cxx']),
+            '.cpp': {'.cc', '.cxx'},
             '.S': set(),
         }
 
         # The inverse of the above, mapping suffixes to their canonical suffix.
         canonicalized_suffix_map = {}
-        for suffix, alternatives in suffix_map.iteritems():
+        for suffix, alternatives in suffix_map.items():
             alternatives.add(suffix)
             for a in alternatives:
                 canonicalized_suffix_map[a] = suffix
@@ -741,7 +739,7 @@ class TreeMetadataEmitter(LoggingMixin):
                     obj = cls(*arglist)
                     yield obj
 
-        for f, flags in all_flags.iteritems():
+        for f, flags in all_flags.items():
             if flags.flags:
                 ext = mozpath.splitext(f)[1]
                 yield PerSourceFlag(context, f, flags.flags)
@@ -772,7 +770,7 @@ class TreeMetadataEmitter(LoggingMixin):
 
         # We always emit a directory traversal descriptor. This is needed by
         # the recursive make backend.
-        for o in self._emit_directory_traversal_from_context(context): yield o
+        yield from self._emit_directory_traversal_from_context(context)
 
         for obj in self._process_xpidl(context):
             yield obj
@@ -885,7 +883,7 @@ class TreeMetadataEmitter(LoggingMixin):
         for obj in self._handle_linkables(context, passthru, generated_files):
             yield obj
 
-        generated_files.update(['%s%s' % (k, self.config.substs.get('BIN_SUFFIX', '')) for k in self._binaries.keys()])
+        generated_files.update(['{}{}'.format(k, self.config.substs.get('BIN_SUFFIX', '')) for k in self._binaries.keys()])
 
         components = []
         for var, cls in (
@@ -1033,7 +1031,7 @@ class TreeMetadataEmitter(LoggingMixin):
             script = mozpath.join(mozpath.dirname(mozpath.dirname(__file__)),
                                   'action', 'process_define_files.py')
             yield GeneratedFile(context, script, 'process_define_file',
-                                unicode(path),
+                                str(path),
                                 [Path(context, path + '.in')])
 
         generated_files = context.get('GENERATED_FILES')
@@ -1078,23 +1076,19 @@ class TreeMetadataEmitter(LoggingMixin):
     def _process_test_manifests(self, context):
         for prefix, info in TEST_MANIFESTS.items():
             for path, manifest in context.get('%s_MANIFESTS' % prefix, []):
-                for obj in self._process_test_manifest(context, info, path, manifest):
-                    yield obj
+                yield from self._process_test_manifest(context, info, path, manifest)
 
         for flavor in REFTEST_FLAVORS:
             for path, manifest in context.get('%s_MANIFESTS' % flavor.upper(), []):
-                for obj in self._process_reftest_manifest(context, flavor, path, manifest):
-                    yield obj
+                yield from self._process_reftest_manifest(context, flavor, path, manifest)
 
         for flavor in WEB_PLATFORM_TESTS_FLAVORS:
             for path, manifest in context.get("%s_MANIFESTS" % flavor.upper().replace('-', '_'), []):
-                for obj in self._process_web_platform_tests_manifest(context, path, manifest):
-                    yield obj
+                yield from self._process_web_platform_tests_manifest(context, path, manifest)
 
         python_tests = context.get('PYTHON_UNIT_TESTS')
         if python_tests:
-            for obj in self._process_python_tests(context, python_tests):
-                yield obj
+            yield from self._process_python_tests(context, python_tests)
 
     def _process_test_manifest(self, context, info, manifest_path, mpmanifest):
         flavor, install_root, install_subdir, package_tests = info
diff --git a/python/mozbuild/mozbuild/frontend/gyp_reader.py b/python/mozbuild/mozbuild/frontend/gyp_reader.py
index e6d2607032..af9c0c22a1 100644
--- a/python/mozbuild/mozbuild/frontend/gyp_reader.py
+++ b/python/mozbuild/mozbuild/frontend/gyp_reader.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import gyp
 import gyp.msvs_emulation
@@ -42,18 +41,19 @@ script_dir = mozpath.join(chrome_src, 'build')
 
 
 def encode(value):
-    if isinstance(value, unicode):
-        return value.encode('utf-8')
+    # Python 3: gyp expects plain str, not bytes
+    if isinstance(value, bytes):
+        return value.decode('utf-8')
     return value
 
 
 # Default variables gyp uses when evaluating gyp files.
 generator_default_variables = {
 }
-for dirname in [b'INTERMEDIATE_DIR', b'SHARED_INTERMEDIATE_DIR', b'PRODUCT_DIR',
-                b'LIB_DIR', b'SHARED_LIB_DIR']:
+for dirname in ['INTERMEDIATE_DIR', 'SHARED_INTERMEDIATE_DIR', 'PRODUCT_DIR',
+                'LIB_DIR', 'SHARED_LIB_DIR']:
   # Some gyp steps fail if these are empty(!).
-  generator_default_variables[dirname] = b'$' + dirname
+  generator_default_variables[dirname] = '$' + dirname
 
 for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
                'RULE_INPUT_DIRNAME', 'RULE_INPUT_EXT',
@@ -61,7 +61,7 @@ for unused in ['RULE_INPUT_PATH', 'RULE_INPUT_ROOT', 'RULE_INPUT_NAME',
                'STATIC_LIB_PREFIX', 'STATIC_LIB_SUFFIX',
                'SHARED_LIB_PREFIX', 'SHARED_LIB_SUFFIX',
                'LINKER_SUPPORTS_ICF']:
-  generator_default_variables[unused] = b''
+  generator_default_variables[unused] = ''
 
 
 class GypContext(TemplateContext):
@@ -122,7 +122,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
     # gyp expects plain str instead of unicode. The frontend code gives us
     # unicode strings, so convert them.
     path = encode(path)
-    str_vars = dict((name, encode(value)) for name, value in vars.items())
+    str_vars = {name: encode(value) for name, value in vars.items()}
     if is_msvc:
         # This isn't actually used anywhere in this generator, but it's needed
         # to override the registry detection of VC++ in gyp.
@@ -130,10 +130,10 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
         os.environ['GYP_MSVS_VERSION'] = config.substs['MSVS_VERSION']
 
     params = {
-        b'parallel': False,
-        b'generator_flags': {},
-        b'build_files': [path],
-        b'root_targets': None,
+        'parallel': False,
+        'generator_flags': {},
+        'build_files': [path],
+        'root_targets': None,
     }
 
     if no_chromium:
@@ -149,7 +149,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
 
     # Read the given gyp file and its dependencies.
     generator, flat_list, targets, data = \
-        gyp.Load([path], format=b'mozbuild',
+        gyp.Load([path], format='mozbuild',
             default_variables=str_vars,
             includes=includes,
             depth=encode(depth),
@@ -158,7 +158,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
     # Process all targets from the given gyp files and its dependencies.
     # The path given to AllTargets needs to use os.sep, while the frontend code
     # gives us paths normalized with forward slash separator.
-    for target in gyp.common.AllTargets(flat_list, targets, path.replace(b'/', os.sep)):
+    for target in gyp.common.AllTargets(flat_list, targets, path.replace('/', os.sep)):
         build_file, target_name, toolset = gyp.common.ParseQualifiedTarget(target)
 
         # Each target is given its own objdir. The base of that objdir
@@ -169,7 +169,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
         # and the target_name.
         reldir  = mozpath.relpath(mozpath.dirname(build_file),
                                   mozpath.dirname(path))
-        subdir = '%s_%s' % (
+        subdir = '{}_{}'.format(
             mozpath.splitext(mozpath.basename(build_file))[0],
             target_name,
         )
@@ -234,10 +234,10 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
             if spec['type'] in ('static_library', 'shared_library'):
                 if name.startswith('lib'):
                     name = name[3:]
-                # The context expects an unicode string.
-                context['LIBRARY_NAME'] = name.decode('utf-8')
+                # The context expects a unicode string.
+                context['LIBRARY_NAME'] = name if isinstance(name, str) else name.decode('utf-8')
             else:
-                context['PROGRAM'] = name.decode('utf-8')
+                context['PROGRAM'] = name if isinstance(name, str) else name.decode('utf-8')
             if spec['type'] == 'shared_library':
                 context['FORCE_SHARED_LIB'] = True
             elif spec['type'] == 'static_library' and spec.get('variables', {}).get('no_expand_libs', '0') == '1':
@@ -343,7 +343,7 @@ def read_from_gyp(config, path, output, vars, no_chromium, no_unified, action_ov
                         if not f:
                             continue
                         # the result may be a string or a list.
-                        if isinstance(f, types.StringTypes):
+                        if isinstance(f, (str,)):
                             context[var].append(f)
                         else:
                             context[var].extend(f)
diff --git a/python/mozbuild/mozbuild/frontend/mach_commands.py b/python/mozbuild/mozbuild/frontend/mach_commands.py
index cbecc11375..6d8b56b799 100644
--- a/python/mozbuild/mozbuild/frontend/mach_commands.py
+++ b/python/mozbuild/mozbuild/frontend/mach_commands.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 from collections import defaultdict
 import os
 
@@ -72,7 +72,7 @@ class MozbuildFileCommands(MachCommandBase):
                         print(line)
                     continue
 
-                print('Could not find symbol: %s' % s)
+                print(('Could not find symbol: %s' % s))
                 return 1
 
             return 0
@@ -108,13 +108,13 @@ class MozbuildFileCommands(MachCommandBase):
             for p, m in self._get_files_info(paths, rev=rev).items():
                 components[m.get('BUG_COMPONENT')].add(p)
         except InvalidPathException as e:
-            print(e.message)
+            print((e.message))
             return 1
 
-        for component, files in sorted(components.items(), key=lambda x: (x is None, x)):
-            print('%s :: %s' % (component.product, component.component) if component else 'UNKNOWN')
+        for component, files in sorted(list(components.items()), key=lambda x: (x is None, x)):
+            print(('{} :: {}'.format(component.product, component.component) if component else 'UNKNOWN'))
             for f in sorted(files):
-                print('  %s' % f)
+                print(('  %s' % f))
 
     @SubCommand('file-info', 'missing-bugzilla',
                 'Show files missing Bugzilla component info')
@@ -128,7 +128,7 @@ class MozbuildFileCommands(MachCommandBase):
                 if 'BUG_COMPONENT' not in m:
                     print(p)
         except InvalidPathException as e:
-            print(e.message)
+            print((e.message))
             return 1
 
     @SubCommand('file-info', 'dep-tests',
@@ -140,22 +140,22 @@ class MozbuildFileCommands(MachCommandBase):
     def file_info_test_deps(self, paths, rev=None):
         try:
             for p, m in self._get_files_info(paths, rev=rev).items():
-                print('%s:' % mozpath.relpath(p, self.topsrcdir))
+                print(('%s:' % mozpath.relpath(p, self.topsrcdir)))
                 if m.test_files:
                     print('\tTest file patterns:')
                     for p in m.test_files:
-                        print('\t\t%s' % p)
+                        print(('\t\t%s' % p))
                 if m.test_tags:
                     print('\tRelevant tags:')
                     for p in m.test_tags:
-                        print('\t\t%s' % p)
+                        print(('\t\t%s' % p))
                 if m.test_flavors:
                     print('\tRelevant flavors:')
                     for p in m.test_flavors:
-                        print('\t\t%s' % p)
+                        print(('\t\t%s' % p))
 
         except InvalidPathException as e:
-            print(e.message)
+            print((e.message))
             return 1
 
 
diff --git a/python/mozbuild/mozbuild/frontend/reader.py b/python/mozbuild/mozbuild/frontend/reader.py
index 165a8b7119..1bdec721a0 100644
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -16,7 +16,6 @@ The BuildReader contains basic logic for traversing a tree of mozbuild files.
 It does this by examining specific variables populated during execution.
 """
 
-from __future__ import absolute_import, print_function, unicode_literals
 
 import ast
 import inspect
@@ -81,19 +80,15 @@ from .context import (
 from mozbuild.base import ExecutionSummary
 
 
-if sys.version_info.major == 2:
-    text_type = unicode
-    type_type = types.TypeType
-else:
-    text_type = str
-    type_type = type
+text_type = str
+type_type = type
 
 
 def log(logger, level, action, params, formatter):
     logger.log(level, formatter, extra={'action': action, 'params': params})
 
 
-class EmptyConfig(object):
+class EmptyConfig:
     """A config object that is empty.
 
     This config object is suitable for using with a BuildReader on a vanilla
@@ -309,11 +304,11 @@ class MozbuildSandbox(Sandbox):
             raise Exception('`template` is a function decorator. You must '
                 'use it as `@template` preceding a function declaration.')
 
-        name = func.func_name
+        name = func.__name__
 
         if name in self.templates:
             raise KeyError(
-                'A template named "%s" was already declared in %s.' % (name,
+                'A template named "{}" was already declared in {}.'.format(name,
                 self.templates[name].path))
 
         if name.islower() or name.isupper() or name[0].islower():
@@ -403,12 +398,12 @@ class MozbuildSandbox(Sandbox):
         return template_wrapper
 
 
-class TemplateFunction(object):
+class TemplateFunction:
     def __init__(self, func, sandbox):
-        self.path = func.func_code.co_filename
-        self.name = func.func_name
+        self.path = func.__code__.co_filename
+        self.name = func.__name__
 
-        code = func.func_code
+        code = func.__code__
         firstlineno = code.co_firstlineno
         lines = sandbox._current_source.splitlines(True)
         lines = inspect.getblock(lines[firstlineno - 1:])
@@ -428,7 +423,7 @@ class TemplateFunction(object):
         # actually never calls __getitem__ and __setitem__, so we need to
         # modify the AST so that accesses to globals are properly directed
         # to a dict.
-        self._global_name = b'_data' # AST wants str for this, not unicode
+        self._global_name = '_data' # AST wants str for this
         # In case '_data' is a name used for a variable in the function code,
         # prepend more underscores until we find an unused name.
         while (self._global_name in code.co_names or
@@ -447,8 +442,8 @@ class TemplateFunction(object):
             compile(func_ast, self.path, 'exec'),
             glob,
             self.name,
-            func.func_defaults,
-            func.func_closure,
+            func.__defaults__,
+            func.__closure__,
         )
         func()
 
@@ -462,11 +457,11 @@ class TemplateFunction(object):
             '__builtins__': sandbox._builtins
         }
         func = types.FunctionType(
-            self._func.func_code,
+            self._func.__code__,
             glob,
             self.name,
-            self._func.func_defaults,
-            self._func.func_closure
+            self._func.__defaults__,
+            self._func.__closure__
         )
         sandbox.exec_function(func, args, kwargs, self.path,
                               becomes_current_path=False)
@@ -481,8 +476,8 @@ class TemplateFunction(object):
 
         def visit_Str(self, node):
             # String nodes we got from the AST parser are str, but we want
-            # unicode literals everywhere, so transform them.
-            node.s = unicode(node.s)
+            # str literals everywhere, so transform them.
+            node.s = str(node.s)
             return node
 
         def visit_Name(self, node):
@@ -511,7 +506,7 @@ class SandboxValidationError(Exception):
         s = StringIO()
 
         delim = '=' * 30
-        s.write('\n%s\nERROR PROCESSING MOZBUILD FILE\n%s\n\n' % (delim, delim))
+        s.write('\n{}\nERROR PROCESSING MOZBUILD FILE\n{}\n\n'.format(delim, delim))
 
         s.write('The error occurred while processing the following file or ')
         s.write('one of the files it includes:\n')
@@ -585,7 +580,7 @@ class BuildReaderError(Exception):
         s = StringIO()
 
         delim = '=' * 30
-        s.write('\n%s\nERROR PROCESSING MOZBUILD FILE\n%s\n\n' % (delim, delim))
+        s.write('\n{}\nERROR PROCESSING MOZBUILD FILE\n{}\n\n'.format(delim, delim))
 
         s.write('The error occurred while processing the following file:\n')
         s.write('\n')
@@ -615,7 +610,7 @@ class BuildReaderError(Exception):
 
             for l in traceback.format_exception(type(self.other), self.other,
                 self.trace):
-                s.write(unicode(l))
+                s.write(str(l))
 
         return s.getvalue()
 
@@ -828,7 +823,7 @@ class BuildReaderError(Exception):
         s.write('    %s\n' % traceback.format_exception_only(type(e), e))
 
 
-class BuildReader(object):
+class BuildReader:
     """Read a tree of mozbuild files into data structures.
 
     This is where the build system starts. You give it a tree configuration
@@ -1029,9 +1024,8 @@ class BuildReader(object):
         """
         self._execution_stack.append(path)
         try:
-            for s in self._read_mozbuild(path, config, descend=descend,
-                                         metadata=metadata):
-                yield s
+            yield from self._read_mozbuild(path, config, descend=descend,
+                                         metadata=metadata)
 
         except BuildReaderError as bre:
             raise bre
@@ -1129,7 +1123,7 @@ class BuildReader(object):
                         context)
                 non_unified_sources.add(source)
             action_overrides = {}
-            for action, script in gyp_dir.action_overrides.iteritems():
+            for action, script in gyp_dir.action_overrides.items():
                 action_overrides[action] = SourcePath(context, script)
             time_start = time.time()
             for gyp_context in read_from_gyp(context.config,
@@ -1150,8 +1144,7 @@ class BuildReader(object):
             context['DIRS'].append(mozpath.relpath(gyp_context.objdir, context.objdir))
             sandbox.subcontexts.append(gyp_context)
 
-        for subcontext in sandbox.subcontexts:
-            yield subcontext
+        yield from sandbox.subcontexts
 
         # Traverse into referenced files.
 
@@ -1188,9 +1181,8 @@ class BuildReader(object):
             if not descend:
                 continue
 
-            for res in self.read_mozbuild(child_path, context.config,
-                                          metadata=child_metadata):
-                yield res
+            yield from self.read_mozbuild(child_path, context.config,
+                                          metadata=child_metadata)
 
         self._execution_stack.pop()
 
diff --git a/python/mozbuild/mozbuild/frontend/sandbox.py b/python/mozbuild/mozbuild/frontend/sandbox.py
index 3638ec807c..6f51cbae0c 100644
--- a/python/mozbuild/mozbuild/frontend/sandbox.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox.py
@@ -17,7 +17,6 @@ KeyError are machine parseable. This machine-friendly data is used to present
 user-friendly error messages in the case of errors.
 """
 
-from __future__ import absolute_import, unicode_literals
 
 import os
 import sys
@@ -34,12 +33,11 @@ from mozpack.files import FileFinder
 default_finder = FileFinder('/', find_executables=False)
 
 
-def alphabetical_sorted(iterable, cmp=None, key=lambda x: x.lower(),
-                        reverse=False):
+def alphabetical_sorted(iterable, key=lambda x: x.lower(), reverse=False):
     """sorted() replacement for the sandbox, ordering alphabetically by
     default.
     """
-    return sorted(iterable, cmp, key, reverse)
+    return sorted(iterable, key=key, reverse=reverse)
 
 
 class SandboxError(Exception):
@@ -115,10 +113,10 @@ class Sandbox(dict):
     def __init__(self, context, builtins=None, finder=default_finder):
         """Initialize a Sandbox ready for execution.
         """
-        self._builtins = ReadOnlyDict(
-            (builtins or self.BUILTINS).viewitems() |
-            {b: __builtins__[b] for b in ('__build_class__',)
-             if b in __builtins__}.viewitems())
+        _merged_builtins = dict(builtins or self.BUILTINS)
+        _merged_builtins.update({b: __builtins__[b] for b in ('__build_class__',)
+             if b in __builtins__})
+        self._builtins = ReadOnlyDict(_merged_builtins)
         dict.__setitem__(self, '__builtins__', self._builtins)
 
         assert isinstance(self._builtins, ReadOnlyDict)
@@ -154,6 +152,8 @@ class Sandbox(dict):
 
         try:
             source = self._finder.get(path).read()
+            if isinstance(source, bytes):
+                source = source.decode('utf-8')
         except Exception as e:
             raise SandboxLoadError(self._context.source_stack,
                 sys.exc_info()[2], read_error=path)
diff --git a/python/mozbuild/mozbuild/html_build_viewer.py b/python/mozbuild/mozbuild/html_build_viewer.py
index 5151f04a48..fec427ef9a 100644
--- a/python/mozbuild/mozbuild/html_build_viewer.py
+++ b/python/mozbuild/mozbuild/html_build_viewer.py
@@ -4,16 +4,15 @@
 
 # This module contains code for running an HTTP server to view build info.
 
-from __future__ import absolute_import, unicode_literals
 
-import BaseHTTPServer
+import http.server
 import json
 import os
 
 import requests
 
 
-class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+class HTTPHandler(http.server.BaseHTTPRequestHandler):
     def do_GET(self):
         s = self.server.wrapper
         p = self.path
@@ -82,7 +81,7 @@ class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
             self.wfile.write(fh.read())
 
 
-class BuildViewerServer(object):
+class BuildViewerServer:
     def __init__(self, address='localhost', port=0):
         # TODO use pkg_resources to obtain HTML resources.
         pkg_dir = os.path.dirname(os.path.abspath(__file__))
@@ -92,7 +91,7 @@ class BuildViewerServer(object):
         self.doc_root = doc_root
         self.json_files = {}
 
-        self.server = BaseHTTPServer.HTTPServer((address, port), HTTPHandler)
+        self.server = http.server.HTTPServer((address, port), HTTPHandler)
         self.server.wrapper = self
         self.do_shutdown = False
 
diff --git a/python/mozbuild/mozbuild/jar.py b/python/mozbuild/mozbuild/jar.py
index 98333482b9..6e433978a0 100644
--- a/python/mozbuild/mozbuild/jar.py
+++ b/python/mozbuild/mozbuild/jar.py
@@ -8,16 +8,15 @@ processing jar.mn files.
 See the documentation for jar.mn on MDC for further details on the format.
 '''
 
-from __future__ import absolute_import
 
 import sys
 import os
 import errno
 import re
 import logging
-from time import localtime
+import calendar
 from MozZipFile import ZipFile
-from cStringIO import StringIO
+from io import StringIO
 from collections import defaultdict
 
 from mozbuild.preprocessor import Preprocessor
@@ -59,8 +58,7 @@ class ZipEntry(object):
 def getModTime(aPath):
     if not os.path.isfile(aPath):
         return 0
-    mtime = os.stat(aPath).st_mtime
-    return localtime(mtime)
+    return os.stat(aPath).st_mtime
 
 
 class JarManifestEntry(object):
@@ -95,20 +93,20 @@ class DeprecatedJarManifest(Exception): pass
 
 class JarManifestParser(object):
 
-    ignore = re.compile('\s*(\#.*)?$')
+    ignore = re.compile(r'\s*(\#.*)?$')
     jarline = re.compile('''
         (?:
-            (?:\[(?P<base>[\w\d.\-\_\\\/{}@]+)\]\s*)? # optional [base/path]
-            (?P<jarfile>[\w\d.\-\_\\\/{}]+).jar\:    # filename.jar:
+            (?:\\[(?P<base>[\\w\\d.\\-\\_\\\\/{}@]+)\\]\\s*)? # optional [base/path]
+            (?P<jarfile>[\\w\\d.\\-\\_\\\\/{}]+).jar\\:    # filename.jar:
         |
-            (?:\s*(\#.*)?)                           # comment
-        )\s*$                                        # whitespaces
+            (?:\\s*(\\#.*)?)                           # comment
+        )\\s*$                                        # whitespaces
         ''', re.VERBOSE)
-    relsrcline = re.compile('relativesrcdir\s+(?P<relativesrcdir>.+?):')
-    regline = re.compile('\%\s+(.*)$')
-    entryre = '(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
+    relsrcline = re.compile(r'relativesrcdir\s+(?P<relativesrcdir>.+?):')
+    regline = re.compile(r'\%\s+(.*)$')
+    entryre = r'(?P<optPreprocess>\*)?(?P<optOverwrite>\+?)\s+'
     entryline = re.compile(entryre
-                           + '(?P<output>[\w\d.\-\_\\\/\+\@]+)\s*(\((?P<locale>\%?)(?P<source>[\w\d.\-\_\\\/\@\*]+)\))?\s*$'
+                           + '(?P<output>[\\w\\d.\\-\\_\\\\/\\+\\@]+)\\s*(\\((?P<locale>\\%?)(?P<source>[\\w\\d.\\-\\_\\\\/\\@\\*]+)\\))?\\s*$'
                            )
 
     def __init__(self):
@@ -274,7 +272,7 @@ class JarMaker(object):
                                 chromebasepath.format(''), register)
             if jarname != 'chrome':
                 addEntriesToListFile(chromeManifest,
-                                     ['manifest {0}.manifest'.format(jarname)])
+                                     ['manifest {}.manifest'.format(jarname)])
         if self.useChromeManifest:
             chromebase = os.path.dirname(jarname) + '/'
             self.updateManifest(chromeManifest,
@@ -302,9 +300,9 @@ class JarMaker(object):
         '''updateManifest replaces the % in the chrome registration entries
         with the given chrome base path, and updates the given manifest file.
         '''
-        myregister = dict.fromkeys(map(lambda s: s.replace('%',
-            chromebasepath), register))
-        addEntriesToListFile(manifestPath, myregister.iterkeys())
+        myregister = dict.fromkeys([s.replace('%',
+            chromebasepath) for s in register])
+        addEntriesToListFile(manifestPath, myregister.keys())
 
     def makeJar(self, infile, jardir):
         '''makeJar is the main entry point to JarMaker.
@@ -322,7 +320,7 @@ class JarMaker(object):
         elif self.relativesrcdir:
             self.localedirs = \
                 self.generateLocaleDirs(self.relativesrcdir)
-        if isinstance(infile, basestring):
+        if isinstance(infile, str):
             logging.info('processing ' + infile)
             self.sourcedirs.append(_normpath(os.path.dirname(infile)))
         pp = self.pp.clone()
@@ -372,7 +370,7 @@ class JarMaker(object):
             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)
@@ -445,7 +443,7 @@ class JarMaker(object):
         if realsrc is None:
             if jf is not None:
                 jf.close()
-            raise RuntimeError('File "{0}" not found in {1}'.format(src,
+            raise RuntimeError('File "{}" not found in {}'.format(src,
                                ', '.join(src_base)))
 
         if out in self._seen_output:
@@ -458,9 +456,15 @@ class JarMaker(object):
             pp = self.pp.clone()
             if src[-4:] == '.css':
                 pp.setMarker('%')
-            pp.out = outf
+            buf = StringIO()
+            pp.out = buf
             pp.do_include(inf)
             pp.warnUnused(realsrc)
+            content = buf.getvalue()
+            if hasattr(outf, 'mode') and 'b' in outf.mode:
+                outf.write(content.encode('utf-8'))
+            else:
+                outf.write(content)
             outf.close()
             inf.close()
             return
@@ -489,7 +493,7 @@ class JarMaker(object):
         def getDestModTime(self, aPath):
             try:
                 info = self.jarfile.getinfo(aPath)
-                return info.date_time
+                return float(calendar.timegm(info.date_time + (0, 0, -1)))
             except:
                 return 0
 
@@ -514,7 +518,7 @@ class JarMaker(object):
             # 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')
@@ -525,7 +529,7 @@ class JarMaker(object):
             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
@@ -541,7 +545,7 @@ class JarMaker(object):
             # 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':
diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py
index 3a81b03be2..ade3779ab2 100644
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import argparse
 import errno
@@ -124,7 +123,7 @@ class TerminalLoggingHandler(logging.Handler):
             self.release()
 
 
-class BuildProgressFooter(object):
+class BuildProgressFooter:
     """Handles display of a build progress indicator in a terminal.
 
     When mach builds inside a blessings-supported terminal, it will render
@@ -550,7 +549,7 @@ class Build(MachCommandBase):
             ppcheck_script = None
         
         if ppcheck_script:
-            ppcheck_cmd = [which.which("python2.7"), ppcheck_script, ppcheck_path]
+            ppcheck_cmd = [sys.executable, ppcheck_script, ppcheck_path]
             ppcheck_result = subprocess.call(ppcheck_cmd, cwd=self.topsrcdir)
         
         if not ppcheck_script or ppcheck_result: 
@@ -575,7 +574,7 @@ class Build(MachCommandBase):
         # Only print build status messages when we have an active
         # monitor.
         if not buildstatus_messages:
-            append_env[b'NO_BUILDSTATUS_MESSAGES'] =  b'1'
+            append_env['NO_BUILDSTATUS_MESSAGES'] = '1'
         status = self._run_make(srcdir=True, filename='client.mk',
             target='configure', line_handler=line_handler, log=False,
             print_directory=False, allow_parallel=False, ensure_exit_code=False,
@@ -1471,7 +1470,7 @@ class MachDebug(MachCommandBase):
             if verbose:
                 print('config substitutions:', file=out)
                 for k in sorted(config.substs):
-                    print('\t%s: %s' % (k, config.substs[k]), file=out)
+                    print('\t{}: {}'.format(k, config.substs[k]), file=out)
 
                 print('config defines:', file=out)
                 for k in sorted(config.defines):
diff --git a/python/mozbuild/mozbuild/makeutil.py b/python/mozbuild/mozbuild/makeutil.py
index fcd45bed23..f2ea2eccd5 100644
--- a/python/mozbuild/mozbuild/makeutil.py
+++ b/python/mozbuild/mozbuild/makeutil.py
@@ -2,15 +2,14 @@
 # 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 os
 import re
-from types import StringTypes
-from collections import Iterable
+StringTypes = (str,)
+from collections.abc import Iterable
 
 
-class Makefile(object):
+class Makefile:
     '''Provides an interface for writing simple makefiles
 
     Instances of this class are created, populated with rules, then
@@ -56,7 +55,7 @@ class Makefile(object):
             guard.dump(fh)
 
 
-class _SimpleOrderedSet(object):
+class _SimpleOrderedSet:
     '''
     Simple ordered set, specialized for used in Rule below only.
     It doesn't expose a complete API, and normalizes path separators
@@ -88,7 +87,7 @@ class _SimpleOrderedSet(object):
         self._list.extend(added)
 
 
-class Rule(object):
+class Rule:
     '''Class handling simple rules in the form:
            target1 target2 ... : dep1 dep2 ...
                    command1
diff --git a/python/mozbuild/mozbuild/milestone.py b/python/mozbuild/mozbuild/milestone.py
index 3ef55d540d..6291ef013c 100644
--- a/python/mozbuild/mozbuild/milestone.py
+++ b/python/mozbuild/mozbuild/milestone.py
@@ -2,8 +2,8 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 import argparse
 import os
 import re
@@ -63,14 +63,14 @@ def main(args):
 
     if options.uaversion:
         # Only expose the major+minor milestone in the UA string.
-        uaversion = "%s.%s" % (get_milestone_major(milestone),
+        uaversion = "{}.{}".format(get_milestone_major(milestone),
                                get_milestone_minor(milestone))
         print(uaversion)
 
     elif options.symbolversion:
         # Only expose major milestone and alpha version. Used for symbol
         # versioning on Linux.
-        symbolversion = "%s%s" % (get_milestone_major(milestone),
+        symbolversion = "{}{}".format(get_milestone_major(milestone),
                                   get_milestone_ab_with_num(milestone))
         print(symbolversion)
     else:
diff --git a/python/mozbuild/mozbuild/mozconfig.py b/python/mozbuild/mozbuild/mozconfig.py
index b2d91561e8..4d2fcdf624 100644
--- a/python/mozbuild/mozbuild/mozconfig.py
+++ b/python/mozbuild/mozbuild/mozconfig.py
@@ -2,8 +2,8 @@
 # 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, unicode_literals
 
+from __future__ import print_function
 import filecmp
 import os
 import re
@@ -57,10 +57,10 @@ class MozconfigLoadException(Exception):
         Exception.__init__(self, message)
 
 
-class MozconfigLoader(object):
+class MozconfigLoader:
     """Handles loading and parsing of mozconfig files."""
 
-    RE_MAKE_VARIABLE = re.compile('''
+    RE_MAKE_VARIABLE = re.compile(r'''
         ^\s*                    # Leading whitespace
         (?P<var>[a-zA-Z_0-9]+)  # Variable name
         \s* [?:]?= \s*          # Assignment operator surrounded by optional
@@ -116,7 +116,7 @@ class MozconfigLoader(object):
                 potential_roots = [self.topsrcdir, os.getcwd()]
                 # Attempt to eliminate duplicates for e.g.
                 # self.topsrcdir == os.curdir.
-                potential_roots = set(os.path.abspath(p) for p in potential_roots)
+                potential_roots = {os.path.abspath(p) for p in potential_roots}
                 existing = [root for root in potential_roots
                             if os.path.exists(os.path.join(root, env_path))]
                 if len(existing) > 1:
diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py
index d0087d31a8..00e7f9382e 100755
--- a/python/mozbuild/mozbuild/mozinfo.py
+++ b/python/mozbuild/mozbuild/mozinfo.py
@@ -5,7 +5,6 @@
 # This module produces a JSON file that provides basic build info and
 # configuration metadata.
 
-from __future__ import absolute_import
 
 import os
 import re
@@ -128,7 +127,7 @@ def write_mozinfo(file, config, env=os.environ):
     and what keys are produced.
     """
     build_conf = build_dict(config, env)
-    if isinstance(file, basestring):
-        file = open(file, 'wb')
+    if isinstance(file, str):
+        file = open(file, 'w')
 
     json.dump(build_conf, file, sort_keys=True, indent=4)
diff --git a/python/mozbuild/mozbuild/preprocessor.py b/python/mozbuild/mozbuild/preprocessor.py
index 2e7eed1ca6..66818a9c8c 100644
--- a/python/mozbuild/mozbuild/preprocessor.py
+++ b/python/mozbuild/mozbuild/preprocessor.py
@@ -1,7 +1,7 @@
 # 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/.
-"""
+r"""
 This is a very primitive line based preprocessor, for times when using
 a C preprocessor isn't an option.
 
@@ -27,7 +27,8 @@ import os
 import re
 from optparse import OptionParser
 import errno
-from makeutil import Makefile
+from .makeutil import Makefile
+from functools import reduce
 
 # hack around win32 mangling our line endings
 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
@@ -56,7 +57,7 @@ class Expression:
         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):
         """
@@ -126,7 +127,7 @@ class Expression:
         Production: '!'? value
         """
         # eat whitespace right away, too
-        not_ws = re.match('!\s*', self.content)
+        not_ws = re.match(r'!\s*', self.content)
         if not not_ws:
             return self.__get_value()
         rv = Expression.__AST('not')
@@ -136,14 +137,14 @@ class Expression:
         return rv
 
     def __get_value(self):
-        """
+        r"""
         Production: ( [0-9]+ | 'defined(' \w+ ')' | \w+ )
         Note that the order is important, and the expression is kind-of
         ambiguous as \w includes 0-9. One could make it unambiguous by
         removing 0-9 from the first char of a string literal.
         """
         rv = None
-        m = re.match('defined\s*\(\s*(\w+)\s*\)', self.content)
+        m = re.match(r'defined\s*\(\s*(\w+)\s*\)', self.content)
         if m:
             word_len = m.end()
             rv = Expression.__ASTLeaf('defined', m.group(1))
@@ -153,17 +154,17 @@ class Expression:
                 value = int(self.content[:word_len])
                 rv = Expression.__ASTLeaf('int', value)
             else:
-                word_len = re.match('\w*', self.content).end()
+                word_len = re.match(r'\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()
+        ws_len = re.match(r'\s*', self.content).end()
         self.__strip(ws_len)
         return
 
@@ -196,7 +197,7 @@ class Expression:
                 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.
@@ -230,7 +231,7 @@ class Expression:
         def __repr__(self):
             return self.value.__repr__()
 
-    class ParseError(StandardError):
+    class ParseError(Exception):
         """
         Error raised when parsing fails.
         It has two members, offset and content, which give the offset of the
@@ -240,7 +241,7 @@ class Expression:
             self.offset = expression.offset
             self.content = expression.content[:3]
         def __str__(self):
-            return 'Unexpected content at offset {0}, "{1}"'.format(self.offset,
+            return 'Unexpected content at offset {}, "{}"'.format(self.offset,
                                                                     self.content)
 
 class Context(dict):
@@ -278,7 +279,7 @@ class Preprocessor:
         self.context = Context()
         for k,v in {'FILE': '',
                     'LINE': 0,
-                    'DIRECTORY': os.path.abspath('.')}.iteritems():
+                    'DIRECTORY': os.path.abspath('.')}.items():
             self.context[k] = v
         self.actionLevel = 0
         self.disableLevel = 0
@@ -292,25 +293,25 @@ class Preprocessor:
         self.cmds = {}
         for cmd, level in {'define': 0,
                            'undef': 0,
-                           'if': sys.maxint,
-                           'ifdef': sys.maxint,
-                           'ifndef': sys.maxint,
+                           'if': sys.maxsize,
+                           'ifdef': sys.maxsize,
+                           'ifndef': sys.maxsize,
                            'else': 1,
                            'elif': 1,
                            'elifdef': 1,
                            'elifndef': 1,
-                           'endif': sys.maxint,
+                           'endif': sys.maxsize,
                            'expand': 0,
                            'literal': 0,
                            'filter': 0,
                            'unfilter': 0,
                            'include': 0,
                            'includesubst': 0,
-                           'error': 0}.iteritems():
+                           'error': 0}.items():
             self.cmds[cmd] = (level, getattr(self, 'do_' + cmd))
         self.out = sys.stdout
         self.setMarker(marker)
-        self.varsubst = re.compile('@(?P<VAR>\w+)@', re.U)
+        self.varsubst = re.compile(r'@(?P<VAR>\w+)@', re.U)
         self.includes = set()
         self.silenceMissingDirectiveWarnings = False
         if defines:
@@ -319,9 +320,9 @@ class Preprocessor:
     def warnUnused(self, file):
         msg = None
         if self.actionLevel == 0 and not self.silenceMissingDirectiveWarnings:
-            sys.stderr.write('{0}: WARNING: no preprocessor directives found\n'.format(file))
+            sys.stderr.write('{}: WARNING: no preprocessor directives found\n'.format(file))
         elif self.actionLevel == 1:
-            sys.stderr.write('{0}: WARNING: no useful preprocessor directives found\n'.format(file))
+            sys.stderr.write('{}: WARNING: no useful preprocessor directives found\n'.format(file))
         pass
 
     def setMarker(self, aMarker):
@@ -332,7 +333,7 @@ class Preprocessor:
         """
         self.marker = aMarker
         if aMarker:
-            self.instruction = re.compile('{0}(?P<cmd>[a-z]+)(?:\s(?P<args>.*))?$'
+            self.instruction = re.compile(r'{}(?P<cmd>[a-z]+)(?:\s(?P<args>.*))?$'
                                           .format(aMarker),
                                           re.U)
             self.comment = re.compile(aMarker, re.U)
@@ -443,7 +444,7 @@ class Preprocessor:
                 except OSError as error:
                     if error.errno != errno.EEXIST:
                         raise
-            return open(path, 'wb')
+            return open(path, 'w')
 
         p = self.getCommandLineParser()
         options, args = p.parse_args(args=args)
@@ -462,7 +463,7 @@ class Preprocessor:
                 raise Preprocessor.Error(self, "--depend doesn't work with stdout",
                                          None)
             try:
-                from makeutil import Makefile
+                from .makeutil import Makefile
             except:
                 raise Preprocessor.Error(self, "--depend requires the "
                                                "mozbuild.makeutil module", None)
@@ -470,7 +471,7 @@ class Preprocessor:
 
         if args:
             for f in args:
-                with open(f, 'rU') as input:
+                with open(f, 'r') as input:
                     self.processFile(input=input, output=out)
             if depfile:
                 mk = Makefile()
@@ -483,7 +484,7 @@ class Preprocessor:
 
     def getCommandLineParser(self, unescapeDefines = False):
         escapedValue = re.compile('".*"$')
-        numberValue = re.compile('\d+$')
+        numberValue = re.compile(r'\d+$')
         def handleD(option, opt, value, parser):
             vals = value.split('=', 1)
             if len(vals) == 1:
@@ -551,7 +552,7 @@ class Preprocessor:
 
     # Variables
     def do_define(self, args):
-        m = re.match('(?P<name>\w+)(?:\s(?P<value>.*))?', args, re.U)
+        m = re.match(r'(?P<name>\w+)(?:\s(?P<value>.*))?', args, re.U)
         if not m:
             raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
         val = ''
@@ -563,7 +564,7 @@ class Preprocessor:
                 pass
         self.context[m.group('name')] = val
     def do_undef(self, args):
-        m = re.match('(?P<name>\w+)$', args, re.U)
+        m = re.match(r'(?P<name>\w+)$', args, re.U)
         if not m:
             raise Preprocessor.Error(self, 'SYNTAX_DEF', args)
         if args in self.context:
@@ -599,7 +600,7 @@ class Preprocessor:
         if self.disableLevel and not replace:
             self.disableLevel += 1
             return
-        if re.match('\W', args, re.U):
+        if re.match(r'\W', args, re.U):
             raise Preprocessor.Error(self, 'INVALID_VAR', args)
         if args not in self.context:
             self.disableLevel = 1
@@ -614,7 +615,7 @@ class Preprocessor:
         if self.disableLevel and not replace:
             self.disableLevel += 1
             return
-        if re.match('\W', args, re.U):
+        if re.match(r'\W', args, re.U):
             raise Preprocessor.Error(self, 'INVALID_VAR', args)
         if args in self.context:
             self.disableLevel = 1
@@ -658,7 +659,7 @@ class Preprocessor:
             self.ifStates.pop()
     # output processing
     def do_expand(self, args):
-        lst = re.split('__(\w+)__', args, re.U)
+        lst = re.split(r'__(\w+)__', args, re.U)
         do_replace = False
         def vsubst(v):
             if v in self.context:
@@ -677,7 +678,7 @@ class Preprocessor:
         current = dict(self.filters)
         for f in filters:
             current[f] = getattr(self, 'filter_' + f)
-        filterNames = current.keys()
+        filterNames = list(current.keys())
         filterNames.sort()
         self.filters = [(fn, current[fn]) for fn in filterNames]
         return
@@ -687,7 +688,7 @@ class Preprocessor:
         for f in filters:
             if f in current:
                 del current[f]
-        filterNames = current.keys()
+        filterNames = list(current.keys())
         filterNames.sort()
         self.filters = [(fn, current[fn]) for fn in filterNames]
         return
@@ -732,7 +733,7 @@ class Preprocessor:
         args can either be a file name, or a file-like object.
         Files should be opened, and will be closed after processing.
         """
-        isName = type(args) == str or type(args) == unicode
+        isName = type(args) == str or type(args) == str
         oldCheckLineNumbers = self.checkLineNumbers
         self.checkLineNumbers = False
         if isName:
@@ -742,12 +743,12 @@ class Preprocessor:
                     args = self.applyFilters(args)
                 if not os.path.isabs(args):
                     args = os.path.join(self.context['DIRECTORY'], args)
-                args = open(args, 'rU')
+                args = open(args, 'r')
             except Preprocessor.Error:
                 raise
             except:
                 raise Preprocessor.Error(self, 'FILE_NOT_FOUND', str(args))
-        self.checkLineNumbers = bool(re.search('\.(js|jsm|java)(?:\.in)?$', args.name))
+        self.checkLineNumbers = bool(re.search(r'\.(js|jsm|java)(?:\.in)?$', args.name))
         oldFile = self.context['FILE']
         oldLine = self.context['LINE']
         oldDir = self.context['DIRECTORY']
@@ -787,7 +788,7 @@ def preprocess(includes=[sys.stdin], defines={},
     pp = Preprocessor(defines=defines,
                       marker=marker)
     for f in includes:
-        with open(f, 'rU') as input:
+        with open(f, 'r') as input:
             pp.processFile(input=input, output=output)
     return pp.includes
 
diff --git a/python/mozbuild/mozbuild/pythonutil.py b/python/mozbuild/mozbuild/pythonutil.py
index 3dba256915..f8dff1323e 100644
--- a/python/mozbuild/mozbuild/pythonutil.py
+++ b/python/mozbuild/mozbuild/pythonutil.py
@@ -2,7 +2,6 @@
 # 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 os
 import sys
diff --git a/python/mozbuild/mozbuild/shellutil.py b/python/mozbuild/mozbuild/shellutil.py
index 185a970ee5..57fa09b77e 100644
--- a/python/mozbuild/mozbuild/shellutil.py
+++ b/python/mozbuild/mozbuild/shellutil.py
@@ -14,13 +14,13 @@ def _tokens2re(**tokens):
     #   (?P<name>pattern)
     # which matches the pattern and captures it in a named match group.
     # The group names and patterns are given as arguments.
-    all_tokens = '|'.join('(?P<%s>%s)' % (name, value)
-                          for name, value in tokens.iteritems())
+    all_tokens = '|'.join('(?P<{}>{})'.format(name, value)
+                          for name, value in tokens.items())
     nonescaped = r'(?<!\\)(?:%s)' % all_tokens
 
     # The final pattern matches either the above pattern, or an escaped
     # backslash, captured in the "escape" match group.
-    return re.compile('(?:%s|%s)' % (nonescaped, r'(?P<escape>\\\\)'))
+    return re.compile('(?:{}|{})'.format(nonescaped, r'(?P<escape>\\\\)'))
 
 UNQUOTED_TOKENS_RE = _tokens2re(
   whitespace=r'[\t\r\n ]+',
@@ -33,7 +33,7 @@ UNQUOTED_TOKENS_RE = _tokens2re(
 DOUBLY_QUOTED_TOKENS_RE = _tokens2re(
   quote='"',
   backslashedquote=r'\\"',
-  special='\$',
+  special=r'\$',
   backslashed=r'\\[^\\"]',
 )
 
@@ -49,7 +49,7 @@ class MetaCharacterException(Exception):
         self.char = char
 
 
-class _ClineSplitter(object):
+class _ClineSplitter:
     '''
     Parses a given command line string and creates a list of command
     and arguments, with wildcard expansion.
diff --git a/python/mozbuild/mozbuild/sphinx.py b/python/mozbuild/mozbuild/sphinx.py
index 0f8e22ca15..8369324b44 100644
--- a/python/mozbuild/mozbuild/sphinx.py
+++ b/python/mozbuild/mozbuild/sphinx.py
@@ -2,14 +2,13 @@
 # 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 importlib
 import os
 import sys
 
-from sphinx.util.compat import Directive
-from sphinx.util.docstrings import prepare_docstring
+from .sphinx.util.compat import Directive
+from .sphinx.util.docstrings import prepare_docstring
 
 
 def function_reference(f, attr, args, doc):
diff --git a/python/mozbuild/mozbuild/test/action/test_buildlist.py b/python/mozbuild/mozbuild/test/action/test_buildlist.py
index 9c2631812d..b711f114e3 100644
--- a/python/mozbuild/mozbuild/test/action/test_buildlist.py
+++ b/python/mozbuild/mozbuild/test/action/test_buildlist.py
@@ -34,17 +34,17 @@ class TestBuildList(unittest.TestCase):
     """Assert that the lines in the file |filename| are equal
     to the contents of the list |l|, in order."""
     l = l[:]
-    f = open(filename, 'r')
+    f = open(filename)
     lines = [line.rstrip() for line in f.readlines()]
     f.close()
     for line in lines:
-      self.assert_(len(l) > 0,
-                   "ran out of expected lines! (expected '{0}', got '{1}')"
+      self.assertTrue(len(l) > 0,
+                   "ran out of expected lines! (expected '{}', got '{}')"
                    .format(l, lines))
       self.assertEqual(line, l.pop(0))
-    self.assert_(len(l) == 0, 
-                 "not enough lines in file! (expected '{0}',"
-                 " got '{1}'".format(l, lines))
+    self.assertTrue(len(l) == 0, 
+                 "not enough lines in file! (expected '{}',"
+                 " got '{}'".format(l, lines))
 
   def test_basic(self):
     "Test that addEntriesToListFile works when file doesn't exist."
diff --git a/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py b/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py
index 4c7f5635e7..91bde4ce50 100644
--- a/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py
+++ b/python/mozbuild/mozbuild/test/action/test_generate_browsersearch.py
@@ -1,9 +1,6 @@
-# -*- coding: utf-8 -*-
-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-from __future__ import unicode_literals
 
 import json
 import os
@@ -43,8 +40,8 @@ class TestGenerateBrowserSearch(unittest.TestCase):
 
     def test_valid_unicode(self):
         o = self._test_one('valid-zh-CN')
-        self.assertEquals(o['default'], '百度')
-        self.assertEquals(o['engines'], ['百度', 'Google'])
+        self.assertEqual(o['default'], '百度')
+        self.assertEqual(o['engines'], ['百度', 'Google'])
 
     def test_invalid_unicode(self):
         with self.assertRaises(UnicodeDecodeError):
diff --git a/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py b/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py
index 5b77608366..902df88c5b 100644
--- a/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py
+++ b/python/mozbuild/mozbuild/test/action/test_package_fennec_apk.py
@@ -1,9 +1,6 @@
-# -*- coding: utf-8 -*-
-
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
-from __future__ import unicode_literals
 
 import os
 import unittest
@@ -41,14 +38,14 @@ class TestPackageFennecAPK(unittest.TestCase):
                          root_files=[data('root_file.txt')])
 
         # omni.ja ends up in assets/omni.ja.
-        self.assertEquals(jarrer['assets/omni.ja'].open().read().strip(), 'omni.ja')
+        self.assertEqual(jarrer['assets/omni.ja'].open().read().strip(), 'omni.ja')
 
         # Everything else is in place.
         for name in ('classes.dex',
                      'assets/asset.txt',
                      'lib/lib.txt',
                      'root_file.txt'):
-            self.assertEquals(jarrer[name].open().read().strip(), name)
+            self.assertEqual(jarrer[name].open().read().strip(), name)
 
     def test_inputs(self):
         # Language repacks take updated resources from an ap_ and pack them
@@ -57,8 +54,8 @@ class TestPackageFennecAPK(unittest.TestCase):
         # overrides the first.
         jarrer = package(inputs=[data('input2.apk'), data('input1.ap_')])
 
-        files1 = JarReader(data('input1.ap_')).entries.keys()
-        files2 = JarReader(data('input2.apk')).entries.keys()
+        files1 = list(JarReader(data('input1.ap_')).entries.keys())
+        files2 = list(JarReader(data('input2.apk')).entries.keys())
         for name in files2:
             self.assertTrue(name in files1 or
                             jarrer[name].open().read().startswith('input2/'))
diff --git a/python/mozbuild/mozbuild/test/backend/common.py b/python/mozbuild/mozbuild/test/backend/common.py
index 85ccb10378..ba686c1edd 100644
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import unittest
diff --git a/python/mozbuild/mozbuild/test/backend/test_build.py b/python/mozbuild/mozbuild/test/backend/test_build.py
index d6111d85f7..39b53a277d 100644
--- a/python/mozbuild/mozbuild/test/backend/test_build.py
+++ b/python/mozbuild/mozbuild/test/backend/test_build.py
@@ -2,8 +2,8 @@
 # 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 unicode_literals, print_function
 
+from __future__ import print_function
 import buildconfig
 import os
 import shutil
@@ -70,11 +70,11 @@ class TestBuild(unittest.TestCase):
         try:
             yield handle_make_line
         except:
-            print('\n'.join(lines))
+            print(('\n'.join(lines)))
             raise
 
         if os.environ.get('MOZ_VERBOSE_MAKE'):
-            print('\n'.join(lines))
+            print(('\n'.join(lines)))
 
     def test_recursive_make(self):
         substs = list(BASE_SUBSTS)
diff --git a/python/mozbuild/mozbuild/test/backend/test_configenvironment.py b/python/mozbuild/mozbuild/test/backend/test_configenvironment.py
index 95593e1869..7f233372af 100644
--- a/python/mozbuild/mozbuild/test/backend/test_configenvironment.py
+++ b/python/mozbuild/mozbuild/test/backend/test_configenvironment.py
@@ -29,7 +29,7 @@ class ConfigEnvironment(ConfigStatus.ConfigEnvironment):
             self.substs = ReadOnlyDict(d)
 
             d = dict(self.substs_unicode)
-            d[u'top_srcdir'] = top_srcdir.decode('utf-8')
+            d['top_srcdir'] = top_srcdir.decode('utf-8')
             self.substs_unicode = ReadOnlyDict(d)
 
 
diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
index a592ab55a3..0e3c2ecbb4 100644
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -2,9 +2,8 @@
 # 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 unicode_literals
 
-import cPickle as pickle
+import six.moves.cPickle as pickle
 import json
 import os
 import unittest
@@ -24,6 +23,7 @@ from mozbuild.frontend.reader import BuildReader
 from mozbuild.test.backend.common import BackendTester
 
 import mozpack.path as mozpath
+import six
 
 
 class TestRecursiveMakeTraversal(unittest.TestCase):
@@ -57,7 +57,7 @@ class TestRecursiveMakeTraversal(unittest.TestCase):
         traversal.add('W', dirs=['X'])
         traversal.add('X')
 
-        parallels = set(('G', 'H', 'I', 'J', 'O', 'P', 'Q', 'R', 'U'))
+        parallels = {'G', 'H', 'I', 'J', 'O', 'P', 'Q', 'R', 'U'}
         def filter(current, subdirs):
             return (current, [d for d in subdirs.dirs if d in parallels],
                 [d for d in subdirs.dirs if d not in parallels])
@@ -186,7 +186,7 @@ class TestRecursiveMakeBackend(BackendTester):
 
         p = mozpath.join(env.topobjdir, 'Makefile')
 
-        lines = [l.strip() for l in open(p, 'rt').readlines()[1:] if not l.startswith('#')]
+        lines = [l.strip() for l in open(p).readlines()[1:] if not l.startswith('#')]
         self.assertEqual(lines, [
             'DEPTH := .',
             'topobjdir := %s' % env.topobjdir,
@@ -208,7 +208,7 @@ class TestRecursiveMakeBackend(BackendTester):
         p = mozpath.join(env.topobjdir, 'dir2', 'Makefile')
         self.assertTrue(os.path.exists(p))
 
-        lines = [l.strip() for l in open(p, 'rt').readlines()]
+        lines = [l.strip() for l in open(p).readlines()]
         self.assertEqual(len(lines), 10)
 
         self.assertTrue(lines[0].startswith('# THIS FILE WAS AUTOMATICALLY'))
@@ -219,7 +219,7 @@ class TestRecursiveMakeBackend(BackendTester):
 
         p = mozpath.join(env.topobjdir, 'backend.mk')
 
-        lines = [l.strip() for l in open(p, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(p).readlines()[2:]]
         self.assertEqual(lines, [
             'DIRS := dir1 dir2',
         ])
@@ -230,7 +230,7 @@ class TestRecursiveMakeBackend(BackendTester):
         self._consume('stub0', RecursiveMakeBackend, env=env)
         p = mozpath.join(env.topobjdir, 'backend.mk')
 
-        lines = [l.strip() for l in open(p, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(p).readlines()[2:]]
         self.assertEqual(lines, [
             'DIRS := dir1 dir2 dir3',
         ])
@@ -259,7 +259,7 @@ class TestRecursiveMakeBackend(BackendTester):
 
         p = mozpath.join(env.topobjdir, 'foo')
         self.assertTrue(os.path.exists(p))
-        lines = [l.strip() for l in open(p, 'rt').readlines()]
+        lines = [l.strip() for l in open(p).readlines()]
         self.assertEqual(lines, [
             'TEST = foo',
         ])
@@ -269,7 +269,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('install_substitute_config_files', RecursiveMakeBackend)
 
         root_deps_path = mozpath.join(env.topobjdir, 'root-deps.mk')
-        lines = [l.strip() for l in open(root_deps_path, 'rt').readlines()]
+        lines = [l.strip() for l in open(root_deps_path).readlines()]
 
         # Make sure we actually recurse into the sub directory during export to
         # install the subst file.
@@ -280,7 +280,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('variable_passthru', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         expected = {
             'ALLOW_COMPILER_WARNINGS': [
@@ -341,7 +341,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('sources', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         expected = {
             'ASFILES': [
@@ -391,7 +391,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('generated-files', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         expected = [
             'export:: bar.c',
@@ -436,7 +436,7 @@ class TestRecursiveMakeBackend(BackendTester):
         # EXPORTS files that are also GENERATED_FILES should be handled as
         # INSTALL_TARGETS.
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
         expected = [
             'export:: bar.h',
             'GARBAGE += bar.h',
@@ -517,7 +517,7 @@ class TestRecursiveMakeBackend(BackendTester):
         self.assertTrue(os.path.exists(m_master))
         self.assertTrue(os.path.exists(x_master))
 
-        lines = [l.strip() for l in open(x_master, 'rt').readlines()]
+        lines = [l.strip() for l in open(x_master).readlines()]
         self.assertEqual(lines, [
             '; THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT MODIFY BY HAND.',
             '',
@@ -555,13 +555,13 @@ class TestRecursiveMakeBackend(BackendTester):
         self.assertTrue(os.path.exists(all_tests_path))
         test_installs_path = mozpath.join(env.topobjdir, 'test-installs.pkl')
 
-        with open(test_installs_path, 'r') as fh:
+        with open(test_installs_path) as fh:
             test_installs = pickle.load(fh)
 
         self.assertEqual(set(test_installs.keys()),
-                         set(['child/test_sub.js',
+                         {'child/test_sub.js',
                               'child/data/**',
-                              'child/another-file.sjs']))
+                              'child/another-file.sjs'})
         for key in test_installs.keys():
             self.assertIn(key, test_installs)
 
@@ -661,7 +661,7 @@ class TestRecursiveMakeBackend(BackendTester):
 
         manifest_path = mozpath.join(env.topobjdir,
             'ipc', 'ipdl', 'ipdlsrcs.mk')
-        lines = [l.strip() for l in open(manifest_path, 'rt').readlines()]
+        lines = [l.strip() for l in open(manifest_path).readlines()]
 
         # Handle Windows paths correctly
         topsrcdir = env.topsrcdir.replace(os.sep, '/')
@@ -669,7 +669,7 @@ class TestRecursiveMakeBackend(BackendTester):
         expected = [
             "ALL_IPDLSRCS := bar1.ipdl foo1.ipdl %s/bar/bar.ipdl %s/bar/bar2.ipdlh %s/foo/foo.ipdl %s/foo/foo2.ipdlh" % tuple([topsrcdir] * 4),
             "CPPSRCS := UnifiedProtocols0.cpp",
-            "IPDLDIRS := %s/ipc/ipdl %s/bar %s/foo" % (env.topobjdir, topsrcdir, topsrcdir),
+            "IPDLDIRS := {}/ipc/ipdl {}/bar {}/foo".format(env.topobjdir, topsrcdir, topsrcdir),
         ]
 
         found = [str for str in lines if str.startswith(('ALL_IPDLSRCS',
@@ -682,7 +682,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('defines', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         var = 'DEFINES'
         defines = [val for val in lines if val.startswith(var)]
@@ -695,7 +695,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('host-defines', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         var = 'HOST_DEFINES'
         defines = [val for val in lines if val.startswith(var)]
@@ -708,7 +708,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('local_includes', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         expected = [
             'LOCAL_INCLUDES += -I$(srcdir)/bar/baz',
@@ -723,7 +723,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('generated_includes', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         topobjdir = env.topobjdir.replace('\\', '/')
 
@@ -758,9 +758,9 @@ class TestRecursiveMakeBackend(BackendTester):
         expected[mozpath.join(env.topobjdir, 'final-target')] = [
             'FINAL_TARGET = $(DEPTH)/random-final-target'
         ]
-        for key, expected_rules in expected.iteritems():
+        for key, expected_rules in expected.items():
             backend_path = mozpath.join(key, 'backend.mk')
-            lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+            lines = [l.strip() for l in open(backend_path).readlines()[2:]]
             found = [str for str in lines if
                 str.startswith('FINAL_TARGET') or str.startswith('XPI_NAME') or
                 str.startswith('DIST_SUBDIR')]
@@ -771,7 +771,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('dist-files', RecursiveMakeBackend)
 
         backend_path = mozpath.join(env.topobjdir, 'backend.mk')
-        lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]]
+        lines = [l.strip() for l in open(backend_path).readlines()[2:]]
 
         expected = [
             'DIST_FILES_0 += $(srcdir)/install.rdf',
@@ -789,7 +789,7 @@ class TestRecursiveMakeBackend(BackendTester):
         env = self._consume('test_config', RecursiveMakeBackend)
 
         self.assertEqual(
-            open(os.path.join(env.topobjdir, 'file'), 'r').readlines(), [
+            open(os.path.join(env.topobjdir, 'file')).readlines(), [
                 '#ifdef foo\n',
                 'bar baz\n',
                 '@bar@\n',
@@ -831,7 +831,7 @@ class TestRecursiveMakeBackend(BackendTester):
                            '--no-remove-empty-directories %s %s.manifest)'
         # Commands second.
         for project_name in ['main1', 'main2', 'library1', 'library2']:
-            stem = '%s/android_eclipse/%s' % (env.topobjdir, project_name)
+            stem = '{}/android_eclipse/{}'.format(env.topobjdir, project_name)
             self.assertIn(command_template % (stem, stem), lines)
 
         # Projects declared in subdirectories.
@@ -844,7 +844,7 @@ class TestRecursiveMakeBackend(BackendTester):
 
         for project_name in ['submain', 'sublibrary']:
             # Destination and install manifest are relative to topobjdir.
-            stem = '%s/android_eclipse/%s' % (env.topobjdir, project_name)
+            stem = '{}/android_eclipse/{}'.format(env.topobjdir, project_name)
             self.assertIn(command_template % (stem, stem), lines)
 
     def test_install_manifests_package_tests(self):
diff --git a/python/mozbuild/mozbuild/test/common.py b/python/mozbuild/mozbuild/test/common.py
index 76a39b3138..854e1c8c61 100644
--- a/python/mozbuild/mozbuild/test/common.py
+++ b/python/mozbuild/mozbuild/test/common.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from mach.logging import LoggingManager
 
@@ -17,7 +16,7 @@ log_manager.add_terminal_logging()
 
 # mozconfig is not a reusable type (it's actually a module) so, we
 # have to mock it.
-class MockConfig(object):
+class MockConfig:
     def __init__(self,
                  topsrcdir='/path/to/topsrcdir',
                  extra_substs={},
diff --git a/python/mozbuild/mozbuild/test/configure/common.py b/python/mozbuild/mozbuild/test/configure/common.py
index 5ce04e6091..7bfd819e2c 100644
--- a/python/mozbuild/mozbuild/test/configure/common.py
+++ b/python/mozbuild/mozbuild/test/configure/common.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import copy
 import errno
@@ -37,9 +36,9 @@ def ensure_exe_extension(path):
     return path
 
 
-class ConfigureTestVFS(object):
+class ConfigureTestVFS:
     def __init__(self, paths):
-        self._paths = set(mozpath.abspath(p) for p in paths)
+        self._paths = {mozpath.abspath(p) for p in paths}
 
     def exists(self, path):
         path = mozpath.abspath(path)
@@ -78,10 +77,10 @@ class ConfigureTestSandbox(ConfigureSandbox):
         self._search_path = environ.get('PATH', '').split(os.pathsep)
 
         self._subprocess_paths = {
-            mozpath.abspath(k): v for k, v in paths.iteritems() if v
+            mozpath.abspath(k): v for k, v in paths.items() if v
         }
 
-        paths = paths.keys()
+        paths = list(paths.keys())
 
         environ = dict(environ)
         if 'CONFIG_SHELL' not in environ:
@@ -100,7 +99,7 @@ class ConfigureTestSandbox(ConfigureSandbox):
 
         self.imported_os = ReadOnlyNamespace(path=ReadOnlyNamespace(**os_path))
 
-        super(ConfigureTestSandbox, self).__init__(config, environ, *args,
+        super().__init__(config, environ, *args,
                                                    **kwargs)
 
     def _get_one_import(self, what):
@@ -136,7 +135,7 @@ class ConfigureTestSandbox(ConfigureSandbox):
             )
 
         if what == 'ctypes':
-            class CTypesFunc(object):
+            class CTypesFunc:
                 def __init__(self, func):
                     self._func = func
 
@@ -155,17 +154,17 @@ class ConfigureTestSandbox(ConfigureSandbox):
 
         if what == '_winreg':
             def OpenKey(*args, **kwargs):
-                raise WindowsError()
+                raise OSError()
 
             return ReadOnlyNamespace(
                 HKEY_LOCAL_MACHINE=0,
                 OpenKey=OpenKey,
             )
 
-        return super(ConfigureTestSandbox, self)._get_one_import(what)
+        return super()._get_one_import(what)
 
     def create_unicode_buffer(self, *args, **kwargs):
-        class Buffer(object):
+        class Buffer:
             def __init__(self):
                 self.value = ''
 
@@ -192,7 +191,7 @@ class ConfigureTestSandbox(ConfigureSandbox):
         func = self._subprocess_paths.get(program)
         retcode, stdout, stderr = func(stdin, args[1:])
 
-        class Process(object):
+        class Process:
             def communicate(self, stdin=None):
                 return stdout, stderr
 
diff --git a/python/mozbuild/mozbuild/test/configure/lint.py b/python/mozbuild/mozbuild/test/configure/lint.py
index 9965a60e9d..f97caa34fa 100644
--- a/python/mozbuild/mozbuild/test/configure/lint.py
+++ b/python/mozbuild/mozbuild/test/configure/lint.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import os
 import unittest
@@ -14,6 +13,7 @@ from buildconfig import (
 )
 
 from mozbuild.configure.lint import LintSandbox
+import six
 
 
 test_path = os.path.abspath(__file__)
@@ -42,9 +42,7 @@ class LintMeta(type):
         return type.__new__(mcs, name, bases, attrs)
 
 
-class Lint(unittest.TestCase):
-    __metaclass__ = LintMeta
-
+class Lint(six.with_metaclass(LintMeta, unittest.TestCase)):
     def setUp(self):
         self._curdir = os.getcwd()
         os.chdir(topobjdir)
diff --git a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
index 181c7acbd8..2e90deb0bf 100644
--- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from StringIO import StringIO
 import os
@@ -447,7 +446,7 @@ class TestChecksConfigure(unittest.TestCase):
             checking for a... %s
         ''' % self.OTHER_A))
 
-        dirs = map(mozpath.dirname, (self.OTHER_A, self.KNOWN_A))
+        dirs = list(map(mozpath.dirname, (self.OTHER_A, self.KNOWN_A)))
         config, out, status = self.get_result(textwrap.dedent('''\
             check_prog("A", ("known-a",), paths=["%s"])
         ''' % os.pathsep.join(dirs)))
@@ -457,10 +456,10 @@ class TestChecksConfigure(unittest.TestCase):
             checking for a... %s
         ''' % self.OTHER_A))
 
-        dirs = map(mozpath.dirname, (self.KNOWN_A, self.KNOWN_B))
+        dirs = list(map(mozpath.dirname, (self.KNOWN_A, self.KNOWN_B)))
         config, out, status = self.get_result(textwrap.dedent('''\
-            check_prog("A", ("known-a",), paths=["%s", "%s"])
-        ''' % (os.pathsep.join(dirs), self.OTHER_A)))
+            check_prog("A", ("known-a",), paths=["{}", "{}"])
+        '''.format(os.pathsep.join(dirs), self.OTHER_A)))
         self.assertEqual(status, 0)
         self.assertEqual(config, {'A': self.KNOWN_A})
         self.assertEqual(out, textwrap.dedent('''\
@@ -514,14 +513,14 @@ class TestChecksConfigure(unittest.TestCase):
             'KEYTOOL': keytool,
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
+             checking for jarsigner... {}
+             checking for keytool... {}
+             checking for javac... {}
              checking for javac version... 1.7
-        ''' % (java, javah, jar, jarsigner, keytool, javac)))
+        '''.format(java, javah, jar, jarsigner, keytool, javac)))
 
         # An alternative valid set of tools referred to by JAVA_HOME.
         alt_java = mozpath.abspath('/usr/local/bin/java')
@@ -557,14 +556,14 @@ class TestChecksConfigure(unittest.TestCase):
             'KEYTOOL': alt_keytool,
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
+             checking for jarsigner... {}
+             checking for keytool... {}
+             checking for javac... {}
              checking for javac version... 1.7
-        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
+        '''.format(alt_java, alt_javah, alt_jar, alt_jarsigner,
                alt_keytool, alt_javac)))
 
         # We can use --with-java-bin-path instead of JAVA_HOME to similar
@@ -586,14 +585,14 @@ class TestChecksConfigure(unittest.TestCase):
             'KEYTOOL': alt_keytool,
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
+             checking for jarsigner... {}
+             checking for keytool... {}
+             checking for javac... {}
              checking for javac version... 1.7
-        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
+        '''.format(alt_java, alt_javah, alt_jar, alt_jarsigner,
                alt_keytool, alt_javac)))
 
         # If --with-java-bin-path and JAVA_HOME are both set,
@@ -616,14 +615,14 @@ class TestChecksConfigure(unittest.TestCase):
             'KEYTOOL': alt_keytool,
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
+             checking for jarsigner... {}
+             checking for keytool... {}
+             checking for javac... {}
              checking for javac version... 1.7
-        ''' % (alt_java, alt_javah, alt_jar, alt_jarsigner,
+        '''.format(alt_java, alt_javah, alt_jar, alt_jarsigner,
                alt_keytool, alt_javac)))
 
         def mock_old_javac(_, args):
@@ -648,15 +647,15 @@ class TestChecksConfigure(unittest.TestCase):
             'KEYTOOL': keytool,
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
-             checking for jarsigner... %s
-             checking for keytool... %s
-             checking for javac... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
+             checking for jarsigner... {}
+             checking for keytool... {}
+             checking for javac... {}
              checking for javac version... 
              ERROR: javac 1.7 or higher is required (found 1.6.9)
-        ''' % (java, javah, jar, jarsigner, keytool, javac)))
+        '''.format(java, javah, jar, jarsigner, keytool, javac)))
 
         # Any missing tool is fatal when these checks run.
         del paths[jarsigner]
@@ -673,12 +672,12 @@ class TestChecksConfigure(unittest.TestCase):
             'JARSIGNER': ':',
         })
         self.assertEqual(out, textwrap.dedent('''\
-             checking for java... %s
-             checking for javah... %s
-             checking for jar... %s
+             checking for java... {}
+             checking for javah... {}
+             checking for jar... {}
              checking for jarsigner... not found
-             ERROR: The program jarsigner was not found.  Set $JAVA_HOME to your Java SDK directory or use '--with-java-bin-path={java-bin-dir}'
-        ''' % (java, javah, jar)))
+             ERROR: The program jarsigner was not found.  Set $JAVA_HOME to your Java SDK directory or use '--with-java-bin-path={{java-bin-dir}}'
+        '''.format(java, javah, jar)))
 
     def test_pkg_check_modules(self):
         mock_pkg_config_version = '0.10.0'
@@ -710,10 +709,10 @@ class TestChecksConfigure(unittest.TestCase):
         def get_result(cmd, args=[], extra_paths=None):
             return self.get_result(textwrap.dedent('''\
                 option('--disable-compile-environment', help='compile env')
-                include('%(topsrcdir)s/build/moz.configure/util.configure')
-                include('%(topsrcdir)s/build/moz.configure/checks.configure')
-                include('%(topsrcdir)s/build/moz.configure/pkg.configure')
-            ''' % {'topsrcdir': topsrcdir}) + cmd, args=args, extra_paths=extra_paths,
+                include('{topsrcdir}/build/moz.configure/util.configure')
+                include('{topsrcdir}/build/moz.configure/checks.configure')
+                include('{topsrcdir}/build/moz.configure/pkg.configure')
+            '''.format(topsrcdir=topsrcdir)) + cmd, args=args, extra_paths=extra_paths,
                                                    includes=())
 
         extra_paths = {
@@ -735,12 +734,12 @@ class TestChecksConfigure(unittest.TestCase):
                                             extra_paths=extra_paths)
         self.assertEqual(status, 0)
         self.assertEqual(output, textwrap.dedent('''\
-            checking for pkg_config... %s
-            checking for pkg-config version... %s
+            checking for pkg_config... {}
+            checking for pkg-config version... {}
             checking for valid... yes
             checking MOZ_VALID_CFLAGS... -I/usr/include/valid
             checking MOZ_VALID_LIBS... -lvalid
-        ''' % (mock_pkg_config_path, mock_pkg_config_version)))
+        '''.format(mock_pkg_config_path, mock_pkg_config_version)))
         self.assertEqual(config, {
             'PKG_CONFIG': mock_pkg_config_path,
             'MOZ_VALID_CFLAGS': ('-I/usr/include/valid',),
@@ -751,14 +750,14 @@ class TestChecksConfigure(unittest.TestCase):
                                             extra_paths=extra_paths)
         self.assertEqual(status, 1)
         self.assertEqual(output, textwrap.dedent('''\
-            checking for pkg_config... %s
-            checking for pkg-config version... %s
+            checking for pkg_config... {}
+            checking for pkg-config version... {}
             checking for unknown... no
             ERROR: Package unknown was not found in the pkg-config search path.
             ERROR: Perhaps you should add the directory containing `unknown.pc'
             ERROR: to the PKG_CONFIG_PATH environment variable
             ERROR: No package 'unknown' found
-        ''' % (mock_pkg_config_path, mock_pkg_config_version)))
+        '''.format(mock_pkg_config_path, mock_pkg_config_version)))
         self.assertEqual(config, {
             'PKG_CONFIG': mock_pkg_config_path,
         })
@@ -767,11 +766,11 @@ class TestChecksConfigure(unittest.TestCase):
                                             extra_paths=extra_paths)
         self.assertEqual(status, 1)
         self.assertEqual(output, textwrap.dedent('''\
-            checking for pkg_config... %s
-            checking for pkg-config version... %s
+            checking for pkg_config... {}
+            checking for pkg-config version... {}
             checking for new > 1.1... no
             ERROR: Requested 'new > 1.1' but version of new is 1.1
-        ''' % (mock_pkg_config_path, mock_pkg_config_version)))
+        '''.format(mock_pkg_config_path, mock_pkg_config_version)))
         self.assertEqual(config, {
             'PKG_CONFIG': mock_pkg_config_path,
         })
@@ -788,12 +787,12 @@ class TestChecksConfigure(unittest.TestCase):
         config, output, status = get_result(cmd, extra_paths=extra_paths)
         self.assertEqual(status, 0)
         self.assertEqual(output, textwrap.dedent('''\
-            checking for pkg_config... %s
-            checking for pkg-config version... %s
+            checking for pkg_config... {}
+            checking for pkg-config version... {}
             checking for new > 1.1... no
             WARNING: Requested 'new > 1.1' but version of new is 1.1
             Module not found.
-        ''' % (mock_pkg_config_path, mock_pkg_config_version)))
+        '''.format(mock_pkg_config_path, mock_pkg_config_version)))
         self.assertEqual(config, {
             'PKG_CONFIG': mock_pkg_config_path,
         })
diff --git a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
index 5913dbe3d4..a0ad3a9510 100644
--- a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
+++ b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import os
 import textwrap
diff --git a/python/mozbuild/mozbuild/test/configure/test_configure.py b/python/mozbuild/mozbuild/test/configure/test_configure.py
index df97ba70d9..58c7581862 100644
--- a/python/mozbuild/mozbuild/test/configure/test_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_configure.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from StringIO import StringIO
 import os
@@ -43,7 +42,7 @@ class TestConfigure(unittest.TestCase):
 
         if '--help' in options:
             return out.getvalue(), config
-        self.assertEquals('', out.getvalue())
+        self.assertEqual('', out.getvalue())
         return config
 
     def moz_configure(self, source):
@@ -55,7 +54,7 @@ class TestConfigure(unittest.TestCase):
     def test_defaults(self):
         config = self.get_config()
         self.maxDiff = None
-        self.assertEquals({
+        self.assertEqual({
             'CHOICES': NegativeOptionValue(),
             'DEFAULTED': PositiveOptionValue(('not-simple',)),
             'IS_GCC': NegativeOptionValue(),
@@ -71,9 +70,9 @@ class TestConfigure(unittest.TestCase):
     def test_help(self):
         help, config = self.get_config(['--help'], prog='configure')
 
-        self.assertEquals({}, config)
+        self.assertEqual({}, config)
         self.maxDiff = None
-        self.assertEquals(
+        self.assertEqual(
             'Usage: configure [options]\n'
             '\n'
             'Options: [defaults in brackets after descriptions]\n'
@@ -109,7 +108,7 @@ class TestConfigure(unittest.TestCase):
         ):
             self.assertNotIn('ENABLED_SIMPLE', config)
             self.assertIn('SIMPLE', config)
-            self.assertEquals(NegativeOptionValue(), config['SIMPLE'])
+            self.assertEqual(NegativeOptionValue(), config['SIMPLE'])
 
         for config in (
                 self.get_config(['--enable-simple']),
@@ -117,7 +116,7 @@ class TestConfigure(unittest.TestCase):
         ):
             self.assertIn('ENABLED_SIMPLE', config)
             self.assertIn('SIMPLE', config)
-            self.assertEquals(PositiveOptionValue(), config['SIMPLE'])
+            self.assertEqual(PositiveOptionValue(), config['SIMPLE'])
             self.assertIs(config['SIMPLE'], config['ENABLED_SIMPLE'])
 
         # --enable-simple doesn't take values.
@@ -135,7 +134,7 @@ class TestConfigure(unittest.TestCase):
                                 env={'MOZ_WITH_ENV': '1'}),
         ):
             self.assertIn('WITH_ENV', config)
-            self.assertEquals(NegativeOptionValue(), config['WITH_ENV'])
+            self.assertEqual(NegativeOptionValue(), config['WITH_ENV'])
 
         for config in (
                 self.get_config(['--enable-with-env']),
@@ -145,7 +144,7 @@ class TestConfigure(unittest.TestCase):
                                 env={'MOZ_WITH_ENV': ''}),
         ):
             self.assertIn('WITH_ENV', config)
-            self.assertEquals(PositiveOptionValue(), config['WITH_ENV'])
+            self.assertEqual(PositiveOptionValue(), config['WITH_ENV'])
 
         with self.assertRaises(InvalidOptionError):
             self.get_config(['--enable-with-env=value'])
@@ -160,23 +159,23 @@ class TestConfigure(unittest.TestCase):
             self.get_config(['--enable-values', '--disable-values']),
         ):
             self.assertIn(name, config)
-            self.assertEquals(NegativeOptionValue(), config[name])
+            self.assertEqual(NegativeOptionValue(), config[name])
 
         for config in (
             self.get_config(['--enable-values']),
             self.get_config(['--disable-values', '--enable-values']),
         ):
             self.assertIn(name, config)
-            self.assertEquals(PositiveOptionValue(), config[name])
+            self.assertEqual(PositiveOptionValue(), config[name])
 
         config = self.get_config(['--enable-values=foo'])
         self.assertIn(name, config)
-        self.assertEquals(PositiveOptionValue(('foo',)), config[name])
+        self.assertEqual(PositiveOptionValue(('foo',)), config[name])
 
         config = self.get_config(['--enable-values=foo,bar'])
         self.assertIn(name, config)
         self.assertTrue(config[name])
-        self.assertEquals(PositiveOptionValue(('foo', 'bar')), config[name])
+        self.assertEqual(PositiveOptionValue(('foo', 'bar')), config[name])
 
     def test_values2(self):
         self.test_values('VALUES2')
@@ -187,12 +186,12 @@ class TestConfigure(unittest.TestCase):
     def test_returned_default(self):
         config = self.get_config(['--enable-simple'])
         self.assertIn('DEFAULTED', config)
-        self.assertEquals(
+        self.assertEqual(
             PositiveOptionValue(('simple',)), config['DEFAULTED'])
 
         config = self.get_config(['--disable-simple'])
         self.assertIn('DEFAULTED', config)
-        self.assertEquals(
+        self.assertEqual(
             PositiveOptionValue(('not-simple',)), config['DEFAULTED'])
 
     def test_returned_choices(self):
@@ -200,13 +199,13 @@ class TestConfigure(unittest.TestCase):
             config = self.get_config(
                 ['--enable-values=alpha', '--returned-choices=%s' % val])
             self.assertIn('CHOICES', config)
-            self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])
+            self.assertEqual(PositiveOptionValue((val,)), config['CHOICES'])
 
         for val in ('0', '1', '2'):
             config = self.get_config(
                 ['--enable-values=numeric', '--returned-choices=%s' % val])
             self.assertIn('CHOICES', config)
-            self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])
+            self.assertEqual(PositiveOptionValue((val,)), config['CHOICES'])
 
         with self.assertRaises(InvalidOptionError):
             self.get_config(['--enable-values=numeric',
@@ -218,12 +217,12 @@ class TestConfigure(unittest.TestCase):
     def test_included(self):
         config = self.get_config(env={'CC': 'gcc'})
         self.assertIn('IS_GCC', config)
-        self.assertEquals(config['IS_GCC'], True)
+        self.assertEqual(config['IS_GCC'], True)
 
         config = self.get_config(
             ['--enable-include=extra.configure', '--extra'])
         self.assertIn('EXTRA', config)
-        self.assertEquals(PositiveOptionValue(), config['EXTRA'])
+        self.assertEqual(PositiveOptionValue(), config['EXTRA'])
 
         with self.assertRaises(InvalidOptionError):
             self.get_config(['--extra'])
@@ -231,7 +230,7 @@ class TestConfigure(unittest.TestCase):
     def test_template(self):
         config = self.get_config(env={'CC': 'gcc'})
         self.assertIn('CFLAGS', config)
-        self.assertEquals(config['CFLAGS'], ['-Werror=foobar'])
+        self.assertEqual(config['CFLAGS'], ['-Werror=foobar'])
 
         config = self.get_config(env={'CC': 'clang'})
         self.assertNotIn('CFLAGS', config)
@@ -288,7 +287,7 @@ class TestConfigure(unittest.TestCase):
             sandbox
         )
 
-        import __builtin__
+        import builtins
         self.assertIs(sandbox['foo'](), __builtin__)
 
         exec_(textwrap.dedent('''
@@ -300,7 +299,7 @@ class TestConfigure(unittest.TestCase):
         )
 
         f = sandbox['foo']()
-        self.assertEquals(f.name, os.devnull)
+        self.assertEqual(f.name, os.devnull)
         f.close()
 
         # This unlocks the sandbox
@@ -336,8 +335,8 @@ class TestConfigure(unittest.TestCase):
         self.assertIs(sandbox['foo'](), sandbox)
 
         # Nothing leaked from the function being executed
-        self.assertEquals(sandbox.keys(), ['__builtins__', 'foo'])
-        self.assertEquals(sandbox['__builtins__'], ConfigureSandbox.BUILTINS)
+        self.assertEqual(list(sandbox.keys()), ['__builtins__', 'foo'])
+        self.assertEqual(sandbox['__builtins__'], ConfigureSandbox.BUILTINS)
 
         exec_(textwrap.dedent('''
             @template
@@ -354,7 +353,7 @@ class TestConfigure(unittest.TestCase):
         with self.assertRaises(NameError) as e:
             sandbox._depends[sandbox['bar']].result
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "global name 'sys' is not defined")
 
     def test_apply_imports(self):
@@ -363,7 +362,7 @@ class TestConfigure(unittest.TestCase):
         class CountApplyImportsSandbox(ConfigureSandbox):
             def _apply_imports(self, *args, **kwargs):
                 imports.append((args, kwargs))
-                super(CountApplyImportsSandbox, self)._apply_imports(
+                super()._apply_imports(
                     *args, **kwargs)
 
         config = {}
@@ -380,28 +379,28 @@ class TestConfigure(unittest.TestCase):
             sandbox
         )
 
-        self.assertEquals(len(imports), 1)
+        self.assertEqual(len(imports), 1)
 
     def test_os_path(self):
         config = self.get_config(['--with-imports=%s' % __file__])
         self.assertIn('HAS_ABSPATH', config)
-        self.assertEquals(config['HAS_ABSPATH'], True)
+        self.assertEqual(config['HAS_ABSPATH'], True)
         self.assertIn('HAS_GETATIME', config)
-        self.assertEquals(config['HAS_GETATIME'], True)
+        self.assertEqual(config['HAS_GETATIME'], True)
         self.assertIn('HAS_GETATIME2', config)
-        self.assertEquals(config['HAS_GETATIME2'], False)
+        self.assertEqual(config['HAS_GETATIME2'], False)
 
     def test_template_call(self):
         config = self.get_config(env={'CC': 'gcc'})
         self.assertIn('TEMPLATE_VALUE', config)
-        self.assertEquals(config['TEMPLATE_VALUE'], 42)
+        self.assertEqual(config['TEMPLATE_VALUE'], 42)
         self.assertIn('TEMPLATE_VALUE_2', config)
-        self.assertEquals(config['TEMPLATE_VALUE_2'], 21)
+        self.assertEqual(config['TEMPLATE_VALUE_2'], 21)
 
     def test_template_imports(self):
         config = self.get_config(['--enable-imports-in-template'])
         self.assertIn('PLATFORM', config)
-        self.assertEquals(config['PLATFORM'], sys.platform)
+        self.assertEqual(config['PLATFORM'], sys.platform)
 
     def test_decorators(self):
         config = {}
@@ -419,27 +418,27 @@ class TestConfigure(unittest.TestCase):
             return self.get_config(*args, configure='set_config.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config(['--set-foo'])
         self.assertIn('FOO', config)
-        self.assertEquals(config['FOO'], True)
+        self.assertEqual(config['FOO'], True)
 
         config = get_config(['--set-bar'])
         self.assertNotIn('FOO', config)
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], True)
+        self.assertEqual(config['BAR'], True)
 
         config = get_config(['--set-value=qux'])
         self.assertIn('VALUE', config)
-        self.assertEquals(config['VALUE'], 'qux')
+        self.assertEqual(config['VALUE'], 'qux')
 
         config = get_config(['--set-name=hoge'])
         self.assertIn('hoge', config)
-        self.assertEquals(config['hoge'], True)
+        self.assertEqual(config['hoge'], True)
 
         config = get_config([])
-        self.assertEquals(config, {'BAR': False})
+        self.assertEqual(config, {'BAR': False})
 
         with self.assertRaises(ConfigureError):
             # Both --set-foo and --set-name=FOO are going to try to
@@ -454,11 +453,11 @@ class TestConfigure(unittest.TestCase):
             set_config('QUX', 'qux', when='--with-qux')
         '''):
             config = self.get_config()
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': 'foo',
             })
             config = self.get_config(['--with-qux'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': 'foo',
                 'QUX': 'qux',
             })
@@ -468,27 +467,27 @@ class TestConfigure(unittest.TestCase):
             return self.get_config(*args, configure='set_define.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {'DEFINES': {}})
+        self.assertEqual(config, {'DEFINES': {}})
 
         config = get_config(['--set-foo'])
         self.assertIn('FOO', config['DEFINES'])
-        self.assertEquals(config['DEFINES']['FOO'], True)
+        self.assertEqual(config['DEFINES']['FOO'], True)
 
         config = get_config(['--set-bar'])
         self.assertNotIn('FOO', config['DEFINES'])
         self.assertIn('BAR', config['DEFINES'])
-        self.assertEquals(config['DEFINES']['BAR'], True)
+        self.assertEqual(config['DEFINES']['BAR'], True)
 
         config = get_config(['--set-value=qux'])
         self.assertIn('VALUE', config['DEFINES'])
-        self.assertEquals(config['DEFINES']['VALUE'], 'qux')
+        self.assertEqual(config['DEFINES']['VALUE'], 'qux')
 
         config = get_config(['--set-name=hoge'])
         self.assertIn('hoge', config['DEFINES'])
-        self.assertEquals(config['DEFINES']['hoge'], True)
+        self.assertEqual(config['DEFINES']['hoge'], True)
 
         config = get_config([])
-        self.assertEquals(config['DEFINES'], {'BAR': False})
+        self.assertEqual(config['DEFINES'], {'BAR': False})
 
         with self.assertRaises(ConfigureError):
             # Both --set-foo and --set-name=FOO are going to try to
@@ -503,11 +502,11 @@ class TestConfigure(unittest.TestCase):
             set_define('QUX', 'qux', when='--with-qux')
         '''):
             config = self.get_config()
-            self.assertEquals(config['DEFINES'], {
+            self.assertEqual(config['DEFINES'], {
                 'FOO': 'foo',
             })
             config = self.get_config(['--with-qux'])
-            self.assertEquals(config['DEFINES'], {
+            self.assertEqual(config['DEFINES'], {
                 'FOO': 'foo',
                 'QUX': 'qux',
             })
@@ -518,19 +517,19 @@ class TestConfigure(unittest.TestCase):
                 *args, configure='imply_option/simple.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config([])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config(['--enable-foo'])
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], PositiveOptionValue())
+        self.assertEqual(config['BAR'], PositiveOptionValue())
 
         with self.assertRaises(InvalidOptionError) as e:
             get_config(['--enable-foo', '--disable-bar'])
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "'--enable-bar' implied by '--enable-foo' conflicts with "
             "'--disable-bar' from the command-line")
@@ -541,31 +540,31 @@ class TestConfigure(unittest.TestCase):
                 *args, configure='imply_option/negative.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config([])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config(['--enable-foo'])
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], NegativeOptionValue())
+        self.assertEqual(config['BAR'], NegativeOptionValue())
 
         with self.assertRaises(InvalidOptionError) as e:
             get_config(['--enable-foo', '--enable-bar'])
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "'--disable-bar' implied by '--enable-foo' conflicts with "
             "'--enable-bar' from the command-line")
 
         config = get_config(['--disable-hoge'])
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], NegativeOptionValue())
+        self.assertEqual(config['BAR'], NegativeOptionValue())
 
         with self.assertRaises(InvalidOptionError) as e:
             get_config(['--disable-hoge', '--enable-bar'])
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "'--disable-bar' implied by '--disable-hoge' conflicts with "
             "'--enable-bar' from the command-line")
@@ -576,23 +575,23 @@ class TestConfigure(unittest.TestCase):
                 *args, configure='imply_option/values.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config([])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config(['--enable-foo=a'])
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], PositiveOptionValue(('a',)))
+        self.assertEqual(config['BAR'], PositiveOptionValue(('a',)))
 
         config = get_config(['--enable-foo=a,b'])
         self.assertIn('BAR', config)
-        self.assertEquals(config['BAR'], PositiveOptionValue(('a','b')))
+        self.assertEqual(config['BAR'], PositiveOptionValue(('a','b')))
 
         with self.assertRaises(InvalidOptionError) as e:
             get_config(['--enable-foo=a,b', '--disable-bar'])
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "'--enable-bar=a,b' implied by '--enable-foo' conflicts with "
             "'--disable-bar' from the command-line")
@@ -603,15 +602,15 @@ class TestConfigure(unittest.TestCase):
                 *args, configure='imply_option/infer.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config([])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         with self.assertRaises(InvalidOptionError) as e:
             get_config(['--enable-foo', '--disable-bar'])
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "'--enable-bar' implied by '--enable-foo' conflicts with "
             "'--disable-bar' from the command-line")
@@ -619,7 +618,7 @@ class TestConfigure(unittest.TestCase):
         with self.assertRaises(ConfigureError) as e:
             self.get_config([], configure='imply_option/infer_ko.configure')
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             "Cannot infer what implies '--enable-bar'. Please add a `reason` "
             "to the `imply_option` call.")
@@ -630,25 +629,25 @@ class TestConfigure(unittest.TestCase):
                 *args, configure='imply_option/imm.configure')
 
         help, config = get_config(['--help'])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config = get_config([])
-        self.assertEquals(config, {})
+        self.assertEqual(config, {})
 
         config_path = mozpath.abspath(
             mozpath.join(test_data_path, 'imply_option', 'imm.configure'))
 
-        with self.assertRaisesRegexp(InvalidOptionError,
+        with self.assertRaisesRegex(InvalidOptionError,
             "--enable-foo' implied by 'imply_option at %s:7' conflicts with "
             "'--disable-foo' from the command-line" % config_path):
             get_config(['--disable-foo'])
 
-        with self.assertRaisesRegexp(InvalidOptionError,
+        with self.assertRaisesRegex(InvalidOptionError,
             "--enable-bar=foo,bar' implied by 'imply_option at %s:16' conflicts"
             " with '--enable-bar=a,b,c' from the command-line" % config_path):
             get_config(['--enable-bar=a,b,c'])
 
-        with self.assertRaisesRegexp(InvalidOptionError,
+        with self.assertRaisesRegex(InvalidOptionError,
             "--enable-baz=BAZ' implied by 'imply_option at %s:25' conflicts"
             " with '--enable-baz=QUUX' from the command-line" % config_path):
             get_config(['--enable-baz=QUUX'])
@@ -660,7 +659,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "`--with-foo`, emitted from `%s` line 2, is unknown."
                           % mozpath.join(test_data_path, 'moz.configure'))
 
@@ -675,7 +674,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Unexpected type: 'int'")
 
     def test_imply_option_when(self):
@@ -686,12 +685,12 @@ class TestConfigure(unittest.TestCase):
             set_config('QUX', depends('--with-qux')(lambda x: x))
         '''):
             config = self.get_config()
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'QUX': NegativeOptionValue(),
             })
 
             config = self.get_config(['--with-foo'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'QUX': PositiveOptionValue(),
             })
 
@@ -700,7 +699,7 @@ class TestConfigure(unittest.TestCase):
             with self.moz_configure('option("--with-foo", help="foo")'):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `--with-foo` is not handled ; reference it with a @depends'
         )
@@ -712,7 +711,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `--with-foo` already defined'
         )
@@ -724,7 +723,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `MOZ_FOO` already defined'
         )
@@ -736,7 +735,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `MOZ_FOO` already defined'
         )
@@ -748,7 +747,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `MOZ_FOO` already defined'
         )
@@ -760,7 +759,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Option `--with-foo` already defined'
         )
@@ -776,18 +775,18 @@ class TestConfigure(unittest.TestCase):
             set_config('QUX', depends('--with-qux', when='--with-foo')(lambda x: x))
         '''):
             config = self.get_config()
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': NegativeOptionValue(),
             })
 
             config = self.get_config(['--with-foo'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': PositiveOptionValue(),
                 'QUX': NegativeOptionValue(),
             })
 
             config = self.get_config(['--with-foo', '--with-qux'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': PositiveOptionValue(),
                 'QUX': PositiveOptionValue(),
             })
@@ -795,7 +794,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config(['--with-bar'])
 
-            self.assertEquals(
+            self.assertEqual(
                 e.exception.message,
                 '--with-bar is not available in this configuration'
             )
@@ -803,7 +802,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config(['--with-qux'])
 
-            self.assertEquals(
+            self.assertEqual(
                 e.exception.message,
                 '--with-qux is not available in this configuration'
             )
@@ -811,18 +810,18 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config(['QUX=1'])
 
-            self.assertEquals(
+            self.assertEqual(
                 e.exception.message,
                 'QUX is not available in this configuration'
             )
 
             config = self.get_config(env={'QUX': '1'})
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': NegativeOptionValue(),
             })
 
             help, config = self.get_config(['--help'])
-            self.assertEquals(help, textwrap.dedent('''\
+            self.assertEqual(help, textwrap.dedent('''\
                 Usage: configure [options]
 
                 Options: [defaults in brackets after descriptions]
@@ -833,7 +832,7 @@ class TestConfigure(unittest.TestCase):
             '''))
 
             help, config = self.get_config(['--help', '--with-foo'])
-            self.assertEquals(help, textwrap.dedent('''\
+            self.assertEqual(help, textwrap.dedent('''\
                 Usage: configure [options]
 
                 Options: [defaults in brackets after descriptions]
@@ -851,7 +850,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(ConfigureError) as e:
                 self.get_config()
 
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               '@depends function needs the same `when` as '
                               'options it depends on')
 
@@ -868,7 +867,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(ConfigureError) as e:
                 self.get_config()
 
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               '@depends function needs the same `when` as '
                               'options it depends on')
 
@@ -877,7 +876,7 @@ class TestConfigure(unittest.TestCase):
             with self.moz_configure('include("../foo.configure")'):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Cannot include `%s` because it is not in a subdirectory of `%s`'
             % (mozpath.normpath(mozpath.join(test_data_path, '..',
@@ -892,7 +891,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'Cannot include `%s` because it was included already.'
             % mozpath.normpath(mozpath.join(test_data_path,
@@ -905,7 +904,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message, "Unexpected type: 'int'")
+        self.assertEqual(e.exception.message, "Unexpected type: 'int'")
 
     def test_include_when(self):
         with MockedOpen({
@@ -948,26 +947,26 @@ class TestConfigure(unittest.TestCase):
             '''),
         }):
             config = self.get_config()
-            self.assertEquals(config, {})
+            self.assertEqual(config, {})
 
             config = self.get_config(['--with-foo'])
-            self.assertEquals(config, {})
+            self.assertEqual(config, {})
 
             config = self.get_config(['--with-bar'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'BAR': 'bar',
             })
 
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config(['--with-qux'])
 
-            self.assertEquals(
+            self.assertEqual(
                 e.exception.message,
                 '--with-qux is not available in this configuration'
             )
 
             config = self.get_config(['--with-foo', '--with-foo-really'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': 'foo',
                 'FOO2': True,
             })
@@ -979,7 +978,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message, 'Cannot reassign builtins')
+        self.assertEqual(e.exception.message, 'Cannot reassign builtins')
 
         with self.assertRaises(KeyError) as e:
             with self.moz_configure('''
@@ -987,7 +986,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           'Cannot assign `foo` because it is neither a '
                           '@depends nor a @template')
 
@@ -1000,7 +999,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "@depends needs at least one argument")
 
         with self.assertRaises(ConfigureError) as e:
@@ -1011,7 +1010,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "'--with-foo' is not a known option. Maybe it's "
                           "declared too late?")
 
@@ -1023,7 +1022,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Option must not contain an '='")
 
         with self.assertRaises(TypeError) as e:
@@ -1034,7 +1033,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Cannot use object of type 'int' as argument "
                           "to @depends")
 
@@ -1046,7 +1045,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Cannot decorate generator functions with @depends")
 
         with self.assertRaises(TypeError) as e:
@@ -1055,7 +1054,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Unexpected type: 'int'")
 
         with self.assertRaises(ConfigureError) as e:
@@ -1069,7 +1068,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The `foo` function may not be called")
 
         with self.assertRaises(TypeError) as e:
@@ -1080,7 +1079,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "depends_impl() got an unexpected keyword argument 'foo'")
 
     def test_depends_when(self):
@@ -1105,12 +1104,12 @@ class TestConfigure(unittest.TestCase):
             set_config('QUX', qux)
         '''):
             config = self.get_config()
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': 'foo',
             })
 
             config = self.get_config(['--with-qux'])
-            self.assertEquals(config, {
+            self.assertEqual(config, {
                 'FOO': 'foo',
                 'QUX': 'qux',
             })
@@ -1125,7 +1124,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           '@imports must appear after @template')
 
         with self.assertRaises(ConfigureError) as e:
@@ -1138,7 +1137,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           '@imports must appear after @depends')
 
         for import_ in (
@@ -1155,7 +1154,7 @@ class TestConfigure(unittest.TestCase):
                 ''' % import_):
                     self.get_config()
 
-            self.assertEquals(e.exception.message, "Unexpected type: 'int'")
+            self.assertEqual(e.exception.message, "Unexpected type: 'int'")
 
         with self.assertRaises(TypeError) as e:
             with self.moz_configure('''
@@ -1166,7 +1165,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message, "Unexpected type: 'int'")
+        self.assertEqual(e.exception.message, "Unexpected type: 'int'")
 
         with self.assertRaises(ValueError) as e:
             with self.moz_configure('''
@@ -1176,7 +1175,7 @@ class TestConfigure(unittest.TestCase):
             '''):
                 self.get_config()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Invalid argument to @imports: 'os*'")
 
     def test_only_when(self):
@@ -1231,7 +1230,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config(['--foo'])
 
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               '--foo is not available in this configuration')
 
         # Cannot depend on an option defined in a only_when block, because we
@@ -1242,7 +1241,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(ConfigureError) as e:
                 self.get_config()
 
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               '@depends function needs the same `when` as '
                               'options it depends on')
 
@@ -1259,7 +1258,7 @@ class TestConfigure(unittest.TestCase):
             with self.assertRaises(InvalidOptionError) as e:
                 self.get_config()
 
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               '--foo is not available in this configuration')
 
         # And similarly doesn't fail when the condition is true.
diff --git a/python/mozbuild/mozbuild/test/configure/test_lint.py b/python/mozbuild/mozbuild/test/configure/test_lint.py
index 6ac2bb3562..98b2be974d 100644
--- a/python/mozbuild/mozbuild/test/configure/test_lint.py
+++ b/python/mozbuild/mozbuild/test/configure/test_lint.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from StringIO import StringIO
 import os
@@ -62,7 +61,7 @@ class TestLint(unittest.TestCase):
             '''):
                 self.lint_test()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "`bar` depends on '--help' and `foo`. "
                           "`foo` must depend on '--help'")
 
@@ -85,7 +84,7 @@ class TestLint(unittest.TestCase):
             '''):
                 self.lint_test()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "`bar` depends on '--help' and `foo`. "
                           "`foo` must depend on '--help'")
 
@@ -111,7 +110,7 @@ class TestLint(unittest.TestCase):
             '''):
                 self.lint_test()
 
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "Missing @depends for `foo`: '--help'")
 
         # There is a default restricted `os` module when there is no explicit
diff --git a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py
index 7c318adefd..18653f85df 100644
--- a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 from mozunit import main
 from mozpack import path as mozpath
@@ -23,10 +22,10 @@ class TestMozConfigure(BaseConfigureTest):
             shell = mozpath.abspath('/bin/sh')
             return result.replace('CONFIG_SHELL=%s ' % shell, '')
 
-        self.assertEquals('--enable-application=browser',
+        self.assertEqual('--enable-application=browser',
                           get_value_for(['--enable-application=browser']))
 
-        self.assertEquals('--enable-application=browser '
+        self.assertEqual('--enable-application=browser '
                           'MOZ_PROFILING=1',
                           get_value_for(['--enable-application=browser',
                                          'MOZ_PROFILING=1']))
@@ -35,32 +34,32 @@ class TestMozConfigure(BaseConfigureTest):
             environ={'MOZ_PROFILING': '1'},
             mozconfig='ac_add_options --enable-project=js')
 
-        self.assertEquals('--enable-project=js MOZ_PROFILING=1',
+        self.assertEqual('--enable-project=js MOZ_PROFILING=1',
                           value)
 
         # --disable-js-shell is the default, so it's filtered out.
-        self.assertEquals('--enable-application=browser',
+        self.assertEqual('--enable-application=browser',
                           get_value_for(['--enable-application=browser',
                                          '--disable-js-shell']))
 
         # Normally, --without-foo would be filtered out because that's the
         # default, but since it is a (fake) old-configure option, it always
         # appears.
-        self.assertEquals('--enable-application=browser --without-foo',
+        self.assertEqual('--enable-application=browser --without-foo',
                           get_value_for(['--enable-application=browser',
                                          '--without-foo']))
-        self.assertEquals('--enable-application=browser --with-foo',
+        self.assertEqual('--enable-application=browser --with-foo',
                           get_value_for(['--enable-application=browser',
                                          '--with-foo']))
 
-        self.assertEquals("--enable-application=browser '--with-foo=foo bar'",
+        self.assertEqual("--enable-application=browser '--with-foo=foo bar'",
                           get_value_for(['--enable-application=browser',
                                          '--with-foo=foo bar']))
 
     def test_nsis_version(self):
         this = self
 
-        class FakeNSIS(object):
+        class FakeNSIS:
             def __init__(self, version):
                 self.version = version
 
@@ -80,13 +79,13 @@ class TestMozConfigure(BaseConfigureTest):
         with self.assertRaises(SystemExit) as e:
             check_nsis_version('v3.0a2')
 
-        self.assertEquals(check_nsis_version('v3.0b1'), '3.0b1')
-        self.assertEquals(check_nsis_version('v3.0b2'), '3.0b2')
-        self.assertEquals(check_nsis_version('v3.0rc1'), '3.0rc1')
-        self.assertEquals(check_nsis_version('v3.0'), '3.0')
-        self.assertEquals(check_nsis_version('v3.0-2'), '3.0')
-        self.assertEquals(check_nsis_version('v3.0.1'), '3.0')
-        self.assertEquals(check_nsis_version('v3.1'), '3.1')
+        self.assertEqual(check_nsis_version('v3.0b1'), '3.0b1')
+        self.assertEqual(check_nsis_version('v3.0b2'), '3.0b2')
+        self.assertEqual(check_nsis_version('v3.0rc1'), '3.0rc1')
+        self.assertEqual(check_nsis_version('v3.0'), '3.0')
+        self.assertEqual(check_nsis_version('v3.0-2'), '3.0')
+        self.assertEqual(check_nsis_version('v3.0.1'), '3.0')
+        self.assertEqual(check_nsis_version('v3.1'), '3.1')
 
 
 if __name__ == '__main__':
diff --git a/python/mozbuild/mozbuild/test/configure/test_options.py b/python/mozbuild/mozbuild/test/configure/test_options.py
index e504f9e05f..6e6b3ab6fc 100644
--- a/python/mozbuild/mozbuild/test/configure/test_options.py
+++ b/python/mozbuild/mozbuild/test/configure/test_options.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import unittest
 
@@ -21,145 +20,145 @@ from mozbuild.configure.options import (
 class Option(Option):
     def __init__(self, *args, **kwargs):
         kwargs['help'] = 'Dummy help'
-        super(Option, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
 
 class TestOption(unittest.TestCase):
     def test_option(self):
         option = Option('--option')
-        self.assertEquals(option.prefix, '')
-        self.assertEquals(option.name, 'option')
-        self.assertEquals(option.env, None)
+        self.assertEqual(option.prefix, '')
+        self.assertEqual(option.name, 'option')
+        self.assertEqual(option.env, None)
         self.assertFalse(option.default)
 
         option = Option('--enable-option')
-        self.assertEquals(option.prefix, 'enable')
-        self.assertEquals(option.name, 'option')
-        self.assertEquals(option.env, None)
+        self.assertEqual(option.prefix, 'enable')
+        self.assertEqual(option.name, 'option')
+        self.assertEqual(option.env, None)
         self.assertFalse(option.default)
 
         option = Option('--disable-option')
-        self.assertEquals(option.prefix, 'disable')
-        self.assertEquals(option.name, 'option')
-        self.assertEquals(option.env, None)
+        self.assertEqual(option.prefix, 'disable')
+        self.assertEqual(option.name, 'option')
+        self.assertEqual(option.env, None)
         self.assertTrue(option.default)
 
         option = Option('--with-option')
-        self.assertEquals(option.prefix, 'with')
-        self.assertEquals(option.name, 'option')
-        self.assertEquals(option.env, None)
+        self.assertEqual(option.prefix, 'with')
+        self.assertEqual(option.name, 'option')
+        self.assertEqual(option.env, None)
         self.assertFalse(option.default)
 
         option = Option('--without-option')
-        self.assertEquals(option.prefix, 'without')
-        self.assertEquals(option.name, 'option')
-        self.assertEquals(option.env, None)
+        self.assertEqual(option.prefix, 'without')
+        self.assertEqual(option.name, 'option')
+        self.assertEqual(option.env, None)
         self.assertTrue(option.default)
 
         option = Option('--without-option-foo', env='MOZ_OPTION')
-        self.assertEquals(option.env, 'MOZ_OPTION')
+        self.assertEqual(option.env, 'MOZ_OPTION')
 
         option = Option(env='MOZ_OPTION')
-        self.assertEquals(option.prefix, '')
-        self.assertEquals(option.name, None)
-        self.assertEquals(option.env, 'MOZ_OPTION')
+        self.assertEqual(option.prefix, '')
+        self.assertEqual(option.name, None)
+        self.assertEqual(option.env, 'MOZ_OPTION')
         self.assertFalse(option.default)
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=0, default=('a',))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=1, default=())
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'default must be a bool, a string or a tuple of strings')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=1, default=True)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=1, default=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=2, default=())
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'default must be a bool, a string or a tuple of strings')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=2, default=True)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=2, default=('a',))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs='?', default=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs='+', default=())
-        self.assertEquals(
+        self.assertEqual(
             e.exception.message,
             'default must be a bool, a string or a tuple of strings')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs='+', default=True)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         # --disable options with a nargs value that requires at least one
         # argument need to be given a default.
         with self.assertRaises(InvalidOptionError) as e:
             Option('--disable-option', nargs=1)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--disable-option', nargs='+')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
         # Test nargs inference from default value
         option = Option('--with-foo', default=True)
-        self.assertEquals(option.nargs, 0)
+        self.assertEqual(option.nargs, 0)
 
         option = Option('--with-foo', default=False)
-        self.assertEquals(option.nargs, 0)
+        self.assertEqual(option.nargs, 0)
 
         option = Option('--with-foo', default='a')
-        self.assertEquals(option.nargs, '?')
+        self.assertEqual(option.nargs, '?')
 
         option = Option('--with-foo', default=('a',))
-        self.assertEquals(option.nargs, '?')
+        self.assertEqual(option.nargs, '?')
 
         option = Option('--with-foo', default=('a', 'b'))
-        self.assertEquals(option.nargs, '*')
+        self.assertEqual(option.nargs, '*')
 
         option = Option(env='FOO', default=True)
-        self.assertEquals(option.nargs, 0)
+        self.assertEqual(option.nargs, 0)
 
         option = Option(env='FOO', default=False)
-        self.assertEquals(option.nargs, 0)
+        self.assertEqual(option.nargs, 0)
 
         option = Option(env='FOO', default='a')
-        self.assertEquals(option.nargs, '?')
+        self.assertEqual(option.nargs, '?')
 
         option = Option(env='FOO', default=('a',))
-        self.assertEquals(option.nargs, '?')
+        self.assertEqual(option.nargs, '?')
 
         option = Option(env='FOO', default=('a', 'b'))
-        self.assertEquals(option.nargs, '*')
+        self.assertEqual(option.nargs, '*')
 
     def test_option_option(self):
         for option in (
@@ -169,70 +168,70 @@ class TestOption(unittest.TestCase):
             '--with-option',
             '--without-option',
         ):
-            self.assertEquals(Option(option).option, option)
-            self.assertEquals(Option(option, env='FOO').option, option)
+            self.assertEqual(Option(option).option, option)
+            self.assertEqual(Option(option, env='FOO').option, option)
 
             opt = Option(option, default=False)
-            self.assertEquals(opt.option,
+            self.assertEqual(opt.option,
                               option.replace('-disable-', '-enable-')
                                     .replace('-without-', '-with-'))
 
             opt = Option(option, default=True)
-            self.assertEquals(opt.option,
+            self.assertEqual(opt.option,
                               option.replace('-enable-', '-disable-')
                                     .replace('-with-', '-without-'))
 
-        self.assertEquals(Option(env='FOO').option, 'FOO')
+        self.assertEqual(Option(env='FOO').option, 'FOO')
 
     def test_option_choices(self):
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=3, choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           'Not enough `choices` for `nargs`')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--without-option', nargs=1, choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           'A `default` must be given along with `choices`')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--without-option', nargs='+', choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           'A `default` must be given along with `choices`')
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--without-option', default='c', choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The `default` value must be one of 'a', 'b'")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--without-option', default=('a', 'c',), choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The `default` value must be one of 'a', 'b'")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--without-option', default=('c',), choices=('a', 'b'))
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The `default` value must be one of 'a', 'b'")
 
         option = Option('--with-option', nargs='+', choices=('a', 'b'))
         with self.assertRaises(InvalidOptionError) as e:
             option.get_value('--with-option=c')
-        self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")
+        self.assertEqual(e.exception.message, "'c' is not one of 'a', 'b'")
 
         value = option.get_value('--with-option=b,a')
         self.assertTrue(value)
-        self.assertEquals(PositiveOptionValue(('b', 'a')), value)
+        self.assertEqual(PositiveOptionValue(('b', 'a')), value)
 
         option = Option('--without-option', nargs='*', default='a',
                         choices=('a', 'b'))
         with self.assertRaises(InvalidOptionError) as e:
             option.get_value('--with-option=c')
-        self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")
+        self.assertEqual(e.exception.message, "'c' is not one of 'a', 'b'")
 
         value = option.get_value('--with-option=b,a')
         self.assertTrue(value)
-        self.assertEquals(PositiveOptionValue(('b', 'a')), value)
+        self.assertEqual(PositiveOptionValue(('b', 'a')), value)
 
         # Test nargs inference from choices
         option = Option('--with-option', choices=('a', 'b'))
@@ -243,71 +242,71 @@ class TestOption(unittest.TestCase):
                         choices=('a', 'b', 'c', 'd'))
 
         value = option.get_value('--with-option=+d')
-        self.assertEquals(PositiveOptionValue(('b', 'c', 'd')), value)
+        self.assertEqual(PositiveOptionValue(('b', 'c', 'd')), value)
 
         value = option.get_value('--with-option=-b')
-        self.assertEquals(PositiveOptionValue(('c',)), value)
+        self.assertEqual(PositiveOptionValue(('c',)), value)
 
         value = option.get_value('--with-option=-b,+d')
-        self.assertEquals(PositiveOptionValue(('c','d')), value)
+        self.assertEqual(PositiveOptionValue(('c','d')), value)
 
         # Adding something that is in the default is fine
         value = option.get_value('--with-option=+b')
-        self.assertEquals(PositiveOptionValue(('b', 'c')), value)
+        self.assertEqual(PositiveOptionValue(('b', 'c')), value)
 
         # Removing something that is not in the default is fine, as long as it
         # is one of the choices
         value = option.get_value('--with-option=-a')
-        self.assertEquals(PositiveOptionValue(('b', 'c')), value)
+        self.assertEqual(PositiveOptionValue(('b', 'c')), value)
 
         with self.assertRaises(InvalidOptionError) as e:
             option.get_value('--with-option=-e')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "'e' is not one of 'a', 'b', 'c', 'd'")
 
         # Other "not a choice" errors.
         with self.assertRaises(InvalidOptionError) as e:
             option.get_value('--with-option=+e')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "'e' is not one of 'a', 'b', 'c', 'd'")
 
         with self.assertRaises(InvalidOptionError) as e:
             option.get_value('--with-option=e')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "'e' is not one of 'a', 'b', 'c', 'd'")
 
     def test_option_value_format(self):
         val = PositiveOptionValue()
-        self.assertEquals('--with-value', val.format('--with-value'))
-        self.assertEquals('--with-value', val.format('--without-value'))
-        self.assertEquals('--enable-value', val.format('--enable-value'))
-        self.assertEquals('--enable-value', val.format('--disable-value'))
-        self.assertEquals('--value', val.format('--value'))
-        self.assertEquals('VALUE=1', val.format('VALUE'))
+        self.assertEqual('--with-value', val.format('--with-value'))
+        self.assertEqual('--with-value', val.format('--without-value'))
+        self.assertEqual('--enable-value', val.format('--enable-value'))
+        self.assertEqual('--enable-value', val.format('--disable-value'))
+        self.assertEqual('--value', val.format('--value'))
+        self.assertEqual('VALUE=1', val.format('VALUE'))
 
         val = PositiveOptionValue(('a',))
-        self.assertEquals('--with-value=a', val.format('--with-value'))
-        self.assertEquals('--with-value=a', val.format('--without-value'))
-        self.assertEquals('--enable-value=a', val.format('--enable-value'))
-        self.assertEquals('--enable-value=a', val.format('--disable-value'))
-        self.assertEquals('--value=a', val.format('--value'))
-        self.assertEquals('VALUE=a', val.format('VALUE'))
+        self.assertEqual('--with-value=a', val.format('--with-value'))
+        self.assertEqual('--with-value=a', val.format('--without-value'))
+        self.assertEqual('--enable-value=a', val.format('--enable-value'))
+        self.assertEqual('--enable-value=a', val.format('--disable-value'))
+        self.assertEqual('--value=a', val.format('--value'))
+        self.assertEqual('VALUE=a', val.format('VALUE'))
 
         val = PositiveOptionValue(('a', 'b'))
-        self.assertEquals('--with-value=a,b', val.format('--with-value'))
-        self.assertEquals('--with-value=a,b', val.format('--without-value'))
-        self.assertEquals('--enable-value=a,b', val.format('--enable-value'))
-        self.assertEquals('--enable-value=a,b', val.format('--disable-value'))
-        self.assertEquals('--value=a,b', val.format('--value'))
-        self.assertEquals('VALUE=a,b', val.format('VALUE'))
+        self.assertEqual('--with-value=a,b', val.format('--with-value'))
+        self.assertEqual('--with-value=a,b', val.format('--without-value'))
+        self.assertEqual('--enable-value=a,b', val.format('--enable-value'))
+        self.assertEqual('--enable-value=a,b', val.format('--disable-value'))
+        self.assertEqual('--value=a,b', val.format('--value'))
+        self.assertEqual('VALUE=a,b', val.format('VALUE'))
 
         val = NegativeOptionValue()
-        self.assertEquals('--without-value', val.format('--with-value'))
-        self.assertEquals('--without-value', val.format('--without-value'))
-        self.assertEquals('--disable-value', val.format('--enable-value'))
-        self.assertEquals('--disable-value', val.format('--disable-value'))
-        self.assertEquals('', val.format('--value'))
-        self.assertEquals('VALUE=', val.format('VALUE'))
+        self.assertEqual('--without-value', val.format('--with-value'))
+        self.assertEqual('--without-value', val.format('--without-value'))
+        self.assertEqual('--disable-value', val.format('--enable-value'))
+        self.assertEqual('--disable-value', val.format('--disable-value'))
+        self.assertEqual('', val.format('--value'))
+        self.assertEqual('VALUE=', val.format('VALUE'))
 
     def test_option_value(self, name='option', nargs=0, default=None):
         disabled = name.startswith(('disable-', 'without-'))
@@ -324,28 +323,28 @@ class TestOption(unittest.TestCase):
 
         if nargs in (0, '?', '*') or disabled:
             value = option.get_value('--%s' % name, 'option')
-            self.assertEquals(value, posOptionValue())
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, posOptionValue())
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s' % name)
             if nargs == 1:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes 1 value' % name)
             elif nargs == '+':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes 1 or more values' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes 2 values' % name)
 
         value = option.get_value('')
-        self.assertEquals(value, defaultValue)
-        self.assertEquals(value.origin, 'default')
+        self.assertEqual(value, defaultValue)
+        self.assertEqual(value.origin, 'default')
 
         value = option.get_value(None)
-        self.assertEquals(value, defaultValue)
-        self.assertEquals(value.origin, 'default')
+        self.assertEqual(value, defaultValue)
+        self.assertEqual(value.origin, 'default')
 
         with self.assertRaises(AssertionError):
             value = option.get_value('MOZ_OPTION=', 'environment')
@@ -358,47 +357,47 @@ class TestOption(unittest.TestCase):
 
         if nargs in (1, '?', '*', '+') and not disabled:
             value = option.get_value('--%s=' % name, 'option')
-            self.assertEquals(value, PositiveOptionValue(('',)))
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, PositiveOptionValue(('',)))
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s=' % name)
             if disabled:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'Cannot pass a value to --%s' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes %d values' % (name, nargs))
 
         if nargs in (1, '?', '*', '+') and not disabled:
             value = option.get_value('--%s=foo' % name, 'option')
-            self.assertEquals(value, PositiveOptionValue(('foo',)))
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, PositiveOptionValue(('foo',)))
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s=foo' % name)
             if disabled:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'Cannot pass a value to --%s' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes %d values' % (name, nargs))
 
         if nargs in (2, '*', '+') and not disabled:
             value = option.get_value('--%s=foo,bar' % name, 'option')
-            self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s=foo,bar' % name, 'option')
             if disabled:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'Cannot pass a value to --%s' % name)
             elif nargs == '?':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes 0 or 1 values' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes %d value%s'
                                   % (name, nargs, 's' if nargs != 1 else ''))
 
@@ -406,59 +405,59 @@ class TestOption(unittest.TestCase):
                         default=default)
         if nargs in (0, '?', '*') or disabled:
             value = option.get_value('--%s' % name, 'option')
-            self.assertEquals(value, posOptionValue())
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, posOptionValue())
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s' % name)
             if disabled:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'Cannot pass a value to --%s' % name)
             elif nargs == '+':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes 1 or more values' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes %d value%s'
                                   % (name, nargs, 's' if nargs != 1 else ''))
 
         value = option.get_value('')
-        self.assertEquals(value, defaultValue)
-        self.assertEquals(value.origin, 'default')
+        self.assertEqual(value, defaultValue)
+        self.assertEqual(value.origin, 'default')
 
         value = option.get_value(None)
-        self.assertEquals(value, defaultValue)
-        self.assertEquals(value.origin, 'default')
+        self.assertEqual(value, defaultValue)
+        self.assertEqual(value.origin, 'default')
 
         value = option.get_value('MOZ_OPTION=', 'environment')
-        self.assertEquals(value, NegativeOptionValue())
-        self.assertEquals(value.origin, 'environment')
+        self.assertEqual(value, NegativeOptionValue())
+        self.assertEqual(value.origin, 'environment')
 
         if nargs in (0, '?', '*'):
             value = option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(value, PositiveOptionValue())
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue())
+            self.assertEqual(value.origin, 'environment')
         elif nargs in (1, '+'):
             value = option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('1',)))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('1',)))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(e.exception.message, 'MOZ_OPTION takes 2 values')
+            self.assertEqual(e.exception.message, 'MOZ_OPTION takes 2 values')
 
         if nargs in (1, '?', '*', '+') and not disabled:
             value = option.get_value('--%s=' % name, 'option')
-            self.assertEquals(value, PositiveOptionValue(('',)))
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, PositiveOptionValue(('',)))
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s=' % name, 'option')
             if disabled:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'Cannot pass a value to --%s' % name)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s takes %d values' % (name, nargs))
 
         with self.assertRaises(AssertionError):
@@ -466,26 +465,26 @@ class TestOption(unittest.TestCase):
 
         if nargs in (1, '?', '*', '+'):
             value = option.get_value('MOZ_OPTION=foo', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('foo',)))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('foo',)))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('MOZ_OPTION=foo', 'environment')
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               'MOZ_OPTION takes %d values' % nargs)
 
         if nargs in (2, '*', '+'):
             value = option.get_value('MOZ_OPTION=foo,bar', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('MOZ_OPTION=foo,bar', 'environment')
             if nargs == '?':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'MOZ_OPTION takes 0 or 1 values')
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'MOZ_OPTION takes %d value%s'
                                   % (nargs, 's' if nargs != 1 else ''))
 
@@ -497,26 +496,26 @@ class TestOption(unittest.TestCase):
             env_option.get_value('--%s' % name)
 
         value = env_option.get_value('')
-        self.assertEquals(value, defaultValue)
-        self.assertEquals(value.origin, 'default')
+        self.assertEqual(value, defaultValue)
+        self.assertEqual(value.origin, 'default')
 
         value = env_option.get_value('MOZ_OPTION=', 'environment')
-        self.assertEquals(value, negOptionValue())
-        self.assertEquals(value.origin, 'environment')
+        self.assertEqual(value, negOptionValue())
+        self.assertEqual(value.origin, 'environment')
 
         if nargs in (0, '?', '*'):
             value = env_option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(value, posOptionValue())
+            self.assertEqual(value, posOptionValue())
             self.assertTrue(value)
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value.origin, 'environment')
         elif nargs in (1, '+'):
             value = env_option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('1',)))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('1',)))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 env_option.get_value('MOZ_OPTION=1', 'environment')
-            self.assertEquals(e.exception.message, 'MOZ_OPTION takes 2 values')
+            self.assertEqual(e.exception.message, 'MOZ_OPTION takes 2 values')
 
         with self.assertRaises(AssertionError) as e:
             env_option.get_value('--%s' % name)
@@ -526,26 +525,26 @@ class TestOption(unittest.TestCase):
 
         if nargs in (1, '?', '*', '+'):
             value = env_option.get_value('MOZ_OPTION=foo', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('foo',)))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('foo',)))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 env_option.get_value('MOZ_OPTION=foo', 'environment')
-            self.assertEquals(e.exception.message,
+            self.assertEqual(e.exception.message,
                               'MOZ_OPTION takes %d values' % nargs)
 
         if nargs in (2, '*', '+'):
             value = env_option.get_value('MOZ_OPTION=foo,bar', 'environment')
-            self.assertEquals(value, PositiveOptionValue(('foo', 'bar')))
-            self.assertEquals(value.origin, 'environment')
+            self.assertEqual(value, PositiveOptionValue(('foo', 'bar')))
+            self.assertEqual(value.origin, 'environment')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 env_option.get_value('MOZ_OPTION=foo,bar', 'environment')
             if nargs == '?':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'MOZ_OPTION takes 0 or 1 values')
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   'MOZ_OPTION takes %d value%s'
                                   % (nargs, 's' if nargs != 1 else ''))
 
@@ -557,28 +556,28 @@ class TestOption(unittest.TestCase):
                                         default=default)
 
         value = option.get_value('--%s-option' % disable, 'option')
-        self.assertEquals(value, NegativeOptionValue())
-        self.assertEquals(value.origin, 'option')
+        self.assertEqual(value, NegativeOptionValue())
+        self.assertEqual(value.origin, 'option')
 
         option = self.test_option_value('%s-option' % disable, nargs=nargs,
                                         default=default)
 
         if nargs in (0, '?', '*'):
             value = option.get_value('--%s-option' % enable, 'option')
-            self.assertEquals(value, PositiveOptionValue())
-            self.assertEquals(value.origin, 'option')
+            self.assertEqual(value, PositiveOptionValue())
+            self.assertEqual(value.origin, 'option')
         else:
             with self.assertRaises(InvalidOptionError) as e:
                 option.get_value('--%s-option' % enable, 'option')
             if nargs == 1:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s-option takes 1 value' % enable)
             elif nargs == '+':
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s-option takes 1 or more values'
                                   % enable)
             else:
-                self.assertEquals(e.exception.message,
+                self.assertEqual(e.exception.message,
                                   '--%s-option takes 2 values' % enable)
 
     def test_option_value_with(self):
@@ -587,12 +586,12 @@ class TestOption(unittest.TestCase):
     def test_option_value_invalid_nargs(self):
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs='foo')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "nargs must be a positive integer, '?', '*' or '+'")
 
         with self.assertRaises(InvalidOptionError) as e:
             Option('--option', nargs=-2)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "nargs must be a positive integer, '?', '*' or '+'")
 
     def test_option_value_nargs_1(self):
@@ -603,7 +602,7 @@ class TestOption(unittest.TestCase):
         # A default is required
         with self.assertRaises(InvalidOptionError) as e:
             Option('--disable-option', nargs=1)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
     def test_option_value_nargs_2(self):
@@ -614,7 +613,7 @@ class TestOption(unittest.TestCase):
         # A default is required
         with self.assertRaises(InvalidOptionError) as e:
             Option('--disable-option', nargs=2)
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
     def test_option_value_nargs_0_or_1(self):
@@ -641,7 +640,7 @@ class TestOption(unittest.TestCase):
         # A default is required
         with self.assertRaises(InvalidOptionError) as e:
             Option('--disable-option', nargs='+')
-        self.assertEquals(e.exception.message,
+        self.assertEqual(e.exception.message,
                           "The given `default` doesn't satisfy `nargs`")
 
 
@@ -649,109 +648,109 @@ class TestCommandLineHelper(unittest.TestCase):
     def test_basic(self):
         helper = CommandLineHelper({}, ['cmd', '--foo', '--bar'])
 
-        self.assertEquals(['--foo', '--bar'], list(helper))
+        self.assertEqual(['--foo', '--bar'], list(helper))
 
         helper.add('--enable-qux')
 
-        self.assertEquals(['--foo', '--bar', '--enable-qux'], list(helper))
+        self.assertEqual(['--foo', '--bar', '--enable-qux'], list(helper))
 
         value, option = helper.handle(Option('--bar'))
-        self.assertEquals(['--foo', '--enable-qux'], list(helper))
-        self.assertEquals(PositiveOptionValue(), value)
-        self.assertEquals('--bar', option)
+        self.assertEqual(['--foo', '--enable-qux'], list(helper))
+        self.assertEqual(PositiveOptionValue(), value)
+        self.assertEqual('--bar', option)
 
         value, option = helper.handle(Option('--baz'))
-        self.assertEquals(['--foo', '--enable-qux'], list(helper))
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals(None, option)
+        self.assertEqual(['--foo', '--enable-qux'], list(helper))
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual(None, option)
 
     def test_precedence(self):
         foo = Option('--with-foo', nargs='*')
         helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--with-foo=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--with-foo=a,b', option)
 
         helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b',
                                         '--without-foo'])
         value, option = helper.handle(foo)
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--without-foo', option)
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--without-foo', option)
 
         helper = CommandLineHelper({}, ['cmd', '--without-foo',
                                         '--with-foo=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--with-foo=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--with-foo=a,b', option)
 
         foo = Option('--with-foo', env='FOO', nargs='*')
         helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-foo=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--with-foo=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--with-foo=a,b', option)
 
         helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-foo'])
         value, option = helper.handle(foo)
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--without-foo', option)
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--without-foo', option)
 
         helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-bar=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals('environment', value.origin)
-        self.assertEquals('FOO=', option)
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual('environment', value.origin)
+        self.assertEqual('FOO=', option)
 
         helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-bar'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('environment', value.origin)
-        self.assertEquals('FOO=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('environment', value.origin)
+        self.assertEqual('FOO=a,b', option)
 
         helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b', 'FOO='])
         value, option = helper.handle(foo)
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('FOO=', option)
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('FOO=', option)
 
         helper = CommandLineHelper({}, ['cmd', '--without-foo', 'FOO=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('FOO=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('FOO=a,b', option)
 
         helper = CommandLineHelper({}, ['cmd', 'FOO=', '--with-foo=a,b'])
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b')), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--with-foo=a,b', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b')), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--with-foo=a,b', option)
 
         helper = CommandLineHelper({}, ['cmd', 'FOO=a,b', '--without-foo'])
         value, option = helper.handle(foo)
-        self.assertEquals(NegativeOptionValue(), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--without-foo', option)
+        self.assertEqual(NegativeOptionValue(), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--without-foo', option)
 
     def test_extra_args(self):
         foo = Option('--with-foo', env='FOO', nargs='*')
         helper = CommandLineHelper({}, ['cmd'])
         helper.add('FOO=a,b,c', 'other-origin')
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
-        self.assertEquals('other-origin', value.origin)
-        self.assertEquals('FOO=a,b,c', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
+        self.assertEqual('other-origin', value.origin)
+        self.assertEqual('FOO=a,b,c', option)
 
         helper = CommandLineHelper({}, ['cmd'])
         helper.add('FOO=a,b,c', 'other-origin')
         helper.add('--with-foo=a,b,c', 'other-origin')
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
-        self.assertEquals('other-origin', value.origin)
-        self.assertEquals('--with-foo=a,b,c', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
+        self.assertEqual('other-origin', value.origin)
+        self.assertEqual('--with-foo=a,b,c', option)
 
         # Adding conflicting options is not allowed.
         helper = CommandLineHelper({}, ['cmd'])
@@ -771,9 +770,9 @@ class TestCommandLineHelper(unittest.TestCase):
         # But adding the same is allowed.
         helper.add('FOO=a,b,c', 'other-origin')
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
-        self.assertEquals('other-origin', value.origin)
-        self.assertEquals('FOO=a,b,c', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
+        self.assertEqual('other-origin', value.origin)
+        self.assertEqual('FOO=a,b,c', option)
 
         # The same rule as above applies when using the option form vs. the
         # variable form. But we can't detect it when .add is called.
@@ -799,9 +798,9 @@ class TestCommandLineHelper(unittest.TestCase):
         helper.add('FOO=a,b,c', 'other-origin')
         helper.add('--with-foo=a,b,c', 'other-origin')
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
-        self.assertEquals('other-origin', value.origin)
-        self.assertEquals('--with-foo=a,b,c', option)
+        self.assertEqual(PositiveOptionValue(('a', 'b', 'c')), value)
+        self.assertEqual('other-origin', value.origin)
+        self.assertEqual('--with-foo=a,b,c', option)
 
         # Conflicts are also not allowed against what is in the
         # environment/on the command line.
@@ -831,19 +830,19 @@ class TestCommandLineHelper(unittest.TestCase):
         foo = Option('--foo',
                      possible_origins=('command-line',))
         value, option = helper.handle(foo)
-        self.assertEquals(PositiveOptionValue(), value)
-        self.assertEquals('command-line', value.origin)
-        self.assertEquals('--foo', option)
+        self.assertEqual(PositiveOptionValue(), value)
+        self.assertEqual('command-line', value.origin)
+        self.assertEqual('--foo', option)
 
         bar = Option('--bar',
                      possible_origins=('mozconfig',))
-        with self.assertRaisesRegexp(InvalidOptionError,
+        with self.assertRaisesRegex(InvalidOptionError,
             "--bar can not be set by command-line. Values are accepted from: mozconfig"):
             helper.handle(bar)
 
         baz = Option(env='BAZ',
                      possible_origins=('implied',))
-        with self.assertRaisesRegexp(InvalidOptionError,
+        with self.assertRaisesRegex(InvalidOptionError,
             "BAZ=1 can not be set by environment. Values are accepted from: implied"):
             helper.handle(baz)
 
diff --git a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
index be3670e53e..96d4001061 100644
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import logging
 import os
@@ -243,7 +242,7 @@ CLANG_CL_PLATFORM_X86_64 = FakeCompiler(VS_PLATFORM_X86_64, GCC_PLATFORM_X86_64[
 
 class BaseToolchainTest(BaseConfigureTest):
     def setUp(self):
-        super(BaseToolchainTest, self).setUp()
+        super().setUp()
         self.out = StringIO()
         self.logger = logging.getLogger('BaseToolchainTest')
         self.logger.setLevel(logging.ERROR)
@@ -254,7 +253,7 @@ class BaseToolchainTest(BaseConfigureTest):
         self.logger.removeHandler(self.handler)
         del self.handler
         del self.out
-        super(BaseToolchainTest, self).tearDown()
+        super().tearDown()
 
     def do_toolchain_test(self, paths, results, args=[], environ={}):
         '''Helper to test the toolchain checks from toolchain.configure.
@@ -291,9 +290,9 @@ class BaseToolchainTest(BaseConfigureTest):
                 compiler = sandbox._value_for(sandbox[var])
                 # Add var on both ends to make it clear which of the
                 # variables is failing the test when that happens.
-                self.assertEquals((var, compiler), (var, result))
+                self.assertEqual((var, compiler), (var, result))
             except SystemExit:
-                self.assertEquals((var, result),
+                self.assertEqual((var, result),
                                   (var, self.out.getvalue().strip()))
                 return
 
@@ -471,7 +470,7 @@ class LinuxToolchainTest(BaseToolchainTest):
         # We'll try gcc and clang, but since there is no gcc (gcc-x.y doesn't
         # count), find clang.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) not in ('gcc', 'g++')
         }
         self.do_toolchain_test(paths, {
@@ -506,7 +505,7 @@ class LinuxToolchainTest(BaseToolchainTest):
         # Even if there are gcc-x.y or clang-x.y compilers available, we
         # don't try them. This could be considered something to improve.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) not in ('gcc', 'g++', 'clang', 'clang++')
         }
         self.do_toolchain_test(paths, {
@@ -687,7 +686,7 @@ class OSXToolchainTest(BaseToolchainTest):
     def test_not_gcc(self):
         # We won't pick GCC if it's the only thing available.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) not in ('clang', 'clang++')
         }
         self.do_toolchain_test(paths, {
@@ -851,7 +850,7 @@ class WindowsToolchainTest(BaseToolchainTest):
     def test_clang_cl(self):
         # We'll pick clang-cl if msvc can't be found.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) != 'cl'
         }
         self.do_toolchain_test(paths, {
@@ -862,7 +861,7 @@ class WindowsToolchainTest(BaseToolchainTest):
     def test_gcc(self):
         # We'll pick GCC if msvc and clang-cl can't be found.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) not in ('cl', 'clang-cl')
         }
         self.do_toolchain_test(paths, {
@@ -881,7 +880,7 @@ class WindowsToolchainTest(BaseToolchainTest):
     def test_clang(self):
         # We'll pick clang if nothing else is found.
         paths = {
-            k: v for k, v in self.PATHS.iteritems()
+            k: v for k, v in self.PATHS.items()
             if os.path.basename(k) not in ('cl', 'clang-cl', 'gcc')
         }
         self.do_toolchain_test(paths, {
@@ -1088,7 +1087,7 @@ class LinuxCrossCompileToolchainTest(BaseToolchainTest):
         self.TARGET = target
         host_cpu = host.split('-')[0]
         cpu, manufacturer, os = target.split('-', 2)
-        toolchain_prefix = '/usr/bin/%s-%s' % (cpu, os)
+        toolchain_prefix = '/usr/bin/{}-{}'.format(cpu, os)
         paths = {
             '/usr/bin/gcc': GCC_4_9 + self.PLATFORMS[host],
             '/usr/bin/g++': GXX_4_9 + self.PLATFORMS[host],
diff --git a/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py b/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
index 8ec33a8b7b..6c218b24a0 100644
--- a/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_helpers.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import copy
 import re
@@ -28,14 +27,14 @@ class CompilerPreprocessor(Preprocessor):
     # For now, we don't look very hard for C strings because they don't matter
     # that much for our unit tests, but we at least avoid expanding in the
     # simple "FOO" case.
-    VARSUBST = re.compile('(?<!")(?P<VAR>\w+)(?!")', re.U)
-    NON_WHITESPACE = re.compile('\S')
-    HAS_FEATURE = re.compile('(__has_feature)\(([^\)]*)\)')
+    VARSUBST = re.compile(r'(?<!")(?P<VAR>\w+)(?!")', re.U)
+    NON_WHITESPACE = re.compile(r'\S')
+    HAS_FEATURE = re.compile(r'(__has_feature)\(([^\)]*)\)')
 
     def __init__(self, *args, **kwargs):
         Preprocessor.__init__(self, *args, **kwargs)
         self.do_filter('c_substitution')
-        self.setMarker('#\s*')
+        self.setMarker(r'#\s*')
 
     def do_if(self, expression, **kwargs):
         # The C preprocessor handles numbers following C rules, which is a
@@ -43,7 +42,7 @@ class CompilerPreprocessor(Preprocessor):
         # Hack around it enough that the configure tests work properly.
         context = self.context
         def normalize_numbers(value):
-            if isinstance(value, types.StringTypes):
+            if isinstance(value, (str,)):
                 if value[-1:] == 'L' and value[:-1].isdigit():
                     value = int(value[:-1])
             return value
@@ -53,7 +52,7 @@ class CompilerPreprocessor(Preprocessor):
             return self.HAS_FEATURE.sub(r'\1\2', expr)
         self.context = self.Context(
             (normalize_has_feature(k), normalize_numbers(v))
-            for k, v in context.iteritems()
+            for k, v in context.items()
         )
         try:
             return Preprocessor.do_if(self, normalize_has_feature(expression),
@@ -95,7 +94,7 @@ class TestCompilerPreprocessor(unittest.TestCase):
         input.name = 'foo'
         pp.do_include(input)
 
-        self.assertEquals(pp.out.getvalue(), '1 . 2 . c "D"')
+        self.assertEqual(pp.out.getvalue(), '1 . 2 . c "D"')
 
     def test_condition(self):
         pp = CompilerPreprocessor({
@@ -125,7 +124,7 @@ class TestCompilerPreprocessor(unittest.TestCase):
         input.name = 'foo'
         pp.do_include(input)
 
-        self.assertEquals('IFDEF_A\nIF_A\nIF_B\nIF_NOT_C\n', pp.out.getvalue())
+        self.assertEqual('IFDEF_A\nIF_A\nIF_B\nIF_NOT_C\n', pp.out.getvalue())
 
 
 class FakeCompiler(dict):
@@ -164,9 +163,9 @@ class FakeCompiler(dict):
     '''
     def __init__(self, *definitions):
         for definition in definitions:
-            if all(not isinstance(d, dict) for d in definition.itervalues()):
+            if all(not isinstance(d, dict) for d in definition.values()):
                 definition = {None: definition}
-            for key, value in definition.iteritems():
+            for key, value in definition.items():
                 self.setdefault(key, {}).update(value)
 
     def __call__(self, stdin, args):
@@ -178,14 +177,14 @@ class FakeCompiler(dict):
             pp = CompilerPreprocessor(self[None])
 
             def apply_defn(defn):
-                for k, v in defn.iteritems():
+                for k, v in defn.items():
                     if v is False:
                         if k in pp.context:
                             del pp.context[k]
                     else:
                         pp.context[k] = v
 
-            for glob, defn in self.iteritems():
+            for glob, defn in self.items():
                 if glob and not glob.startswith('-') and fnmatch(file, glob):
                     apply_defn(defn)
 
@@ -216,7 +215,7 @@ class TestFakeCompiler(unittest.TestCase):
                 'A': '1',
                 'B': '2',
             })
-            self.assertEquals(compiler(None, ['-E', 'file']),
+            self.assertEqual(compiler(None, ['-E', 'file']),
                               (0, '1 2 C', ''))
 
             compiler = FakeCompiler({
@@ -238,25 +237,25 @@ class TestFakeCompiler(unittest.TestCase):
                     'B': '42',
                 },
             })
-            self.assertEquals(compiler(None, ['-E', 'file']),
+            self.assertEqual(compiler(None, ['-E', 'file']),
                               (0, '1 2 C', ''))
-            self.assertEquals(compiler(None, ['-E', '-foo', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-foo', 'file']),
                               (0, '1 2 foo', ''))
-            self.assertEquals(compiler(None, ['-E', '-bar', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-bar', 'file']),
                               (0, '1 bar bar', ''))
-            self.assertEquals(compiler(None, ['-E', '-qux', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-qux', 'file']),
                               (0, '1 B C', ''))
-            self.assertEquals(compiler(None, ['-E', '-foo', '-bar', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-foo', '-bar', 'file']),
                               (0, '1 bar bar', ''))
-            self.assertEquals(compiler(None, ['-E', '-bar', '-foo', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-bar', '-foo', 'file']),
                               (0, '1 bar foo', ''))
-            self.assertEquals(compiler(None, ['-E', '-bar', '-qux', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-bar', '-qux', 'file']),
                               (0, '1 B bar', ''))
-            self.assertEquals(compiler(None, ['-E', '-qux', '-bar', 'file']),
+            self.assertEqual(compiler(None, ['-E', '-qux', '-bar', 'file']),
                               (0, '1 bar bar', ''))
-            self.assertEquals(compiler(None, ['-E', 'file.c']),
+            self.assertEqual(compiler(None, ['-E', 'file.c']),
                               (0, '1 42 C', ''))
-            self.assertEquals(compiler(None, ['-E', '-bar', 'file.c']),
+            self.assertEqual(compiler(None, ['-E', '-bar', 'file.c']),
                               (0, '1 bar bar', ''))
 
     def test_multiple_definitions(self):
@@ -267,7 +266,7 @@ class TestFakeCompiler(unittest.TestCase):
             'C': 3,
         })
 
-        self.assertEquals(compiler, {
+        self.assertEqual(compiler, {
             None: {
                 'A': 1,
                 'B': 2,
@@ -282,7 +281,7 @@ class TestFakeCompiler(unittest.TestCase):
             'C': 3,
         })
 
-        self.assertEquals(compiler, {
+        self.assertEqual(compiler, {
             None: {
                 'A': 1,
                 'B': 4,
@@ -302,7 +301,7 @@ class TestFakeCompiler(unittest.TestCase):
             },
         })
 
-        self.assertEquals(compiler, {
+        self.assertEqual(compiler, {
             None: {
                 'A': 1,
                 'B': 4,
@@ -330,7 +329,7 @@ class TestFakeCompiler(unittest.TestCase):
             },
         })
 
-        self.assertEquals(compiler, {
+        self.assertEqual(compiler, {
             None: {
                 'A': 1,
                 'B': 2,
@@ -358,7 +357,7 @@ class CompilerResult(ReadOnlyNamespace):
             flags = []
         if wrapper is None:
             wrapper = []
-        super(CompilerResult, self).__init__(
+        super().__init__(
             flags=flags,
             version=version,
             type=type,
@@ -370,7 +369,7 @@ class CompilerResult(ReadOnlyNamespace):
     def __add__(self, other):
         assert isinstance(other, dict)
         result = copy.deepcopy(self.__dict__)
-        for k, v in other.iteritems():
+        for k, v in other.items():
             if k == 'flags':
                 result.setdefault(k, []).extend(v)
             else:
@@ -381,7 +380,7 @@ class CompilerResult(ReadOnlyNamespace):
 class TestCompilerResult(unittest.TestCase):
     def test_compiler_result(self):
         result = CompilerResult()
-        self.assertEquals(result.__dict__, {
+        self.assertEqual(result.__dict__, {
             'wrapper': [],
             'compiler': mozpath.abspath(''),
             'version': '',
@@ -397,7 +396,7 @@ class TestCompilerResult(unittest.TestCase):
             language='C',
             flags=['-std=gnu99'],
         )
-        self.assertEquals(result.__dict__, {
+        self.assertEqual(result.__dict__, {
             'wrapper': [],
             'compiler': mozpath.abspath('/usr/bin/gcc'),
             'version': '4.2.1',
@@ -407,7 +406,7 @@ class TestCompilerResult(unittest.TestCase):
         })
 
         result2 = result + {'flags': ['-m32']}
-        self.assertEquals(result2.__dict__, {
+        self.assertEqual(result2.__dict__, {
             'wrapper': [],
             'compiler': mozpath.abspath('/usr/bin/gcc'),
             'version': '4.2.1',
@@ -416,14 +415,14 @@ class TestCompilerResult(unittest.TestCase):
             'flags': ['-std=gnu99', '-m32'],
         })
         # Original flags are untouched.
-        self.assertEquals(result.flags, ['-std=gnu99'])
+        self.assertEqual(result.flags, ['-std=gnu99'])
 
         result3 = result + {
             'compiler': '/usr/bin/gcc-4.7',
             'version': '4.7.3',
             'flags': ['-m32'],
         }
-        self.assertEquals(result3.__dict__, {
+        self.assertEqual(result3.__dict__, {
             'wrapper': [],
             'compiler': mozpath.abspath('/usr/bin/gcc-4.7'),
             'version': '4.7.3',
diff --git a/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py b/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py
index 30dc022b77..9768311ec1 100644
--- a/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py
+++ b/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import os
 
diff --git a/python/mozbuild/mozbuild/test/configure/test_util.py b/python/mozbuild/mozbuild/test/configure/test_util.py
index 38b3c636e5..83111cb542 100644
--- a/python/mozbuild/mozbuild/test/configure/test_util.py
+++ b/python/mozbuild/mozbuild/test/configure/test_util.py
@@ -2,7 +2,6 @@
 # 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, print_function, unicode_literals
 
 import logging
 import os
@@ -434,11 +433,11 @@ class TestLogSubprocessOutput(unittest.TestCase):
         except SystemExit as e:
             status = e.code
 
-        self.assertEquals(status, 0)
+        self.assertEqual(status, 0)
         quote_char = "'"
         if getpreferredencoding().lower() == 'utf-8':
-            quote_char = '\u00B4'.encode('utf-8')
-        self.assertEquals(out.getvalue().strip(), quote_char)
+            quote_char = '\u00B4'.encode()
+        self.assertEqual(out.getvalue().strip(), quote_char)
 
 
 class TestVersion(unittest.TestCase):
@@ -520,14 +519,14 @@ class TestCheckCmdOutput(unittest.TestCase):
         self.assertEqual(config, {})
         self.assertEqual(status, 1)
         self.assertEqual(out, textwrap.dedent('''\
-            DEBUG: Executing: `%s --error`
+            DEBUG: Executing: `{} --error`
             DEBUG: The command returned non-zero exit status 127.
             DEBUG: Its output was:
             DEBUG: | simple program output
             DEBUG: Its error output was:
             DEBUG: | simple program error output
-            ERROR: Command `%s --error` failed with exit status 127.
-        ''' % (prog_path, prog_path)))
+            ERROR: Command `{} --error` failed with exit status 127.
+        '''.format(prog_path, prog_path)))
 
     def test_error_callback(self):
         def mock_error_prog(_, args):
diff --git a/python/mozbuild/mozbuild/test/controller/test_ccachestats.py b/python/mozbuild/mozbuild/test/controller/test_ccachestats.py
index 7a6608ec8f..94d47cfba7 100644
--- a/python/mozbuild/mozbuild/test/controller/test_ccachestats.py
+++ b/python/mozbuild/mozbuild/test/controller/test_ccachestats.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import unittest
 
diff --git a/python/mozbuild/mozbuild/test/controller/test_clobber.py b/python/mozbuild/mozbuild/test/controller/test_clobber.py
index 997f467ecd..129108c00f 100644
--- a/python/mozbuild/mozbuild/test/controller/test_clobber.py
+++ b/python/mozbuild/mozbuild/test/controller/test_clobber.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import shutil
diff --git a/python/mozbuild/mozbuild/test/frontend/test_context.py b/python/mozbuild/mozbuild/test/frontend/test_context.py
index 070cfad670..c0c95a9050 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_context.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_context.py
@@ -36,7 +36,7 @@ class TestContext(unittest.TestCase):
             'baz': (dict, dict, ''),
         })
 
-        self.assertEqual(test.keys(), [])
+        self.assertEqual(list(test.keys()), [])
 
         self.assertEqual(test['foo'], 0)
 
@@ -84,12 +84,12 @@ class TestContext(unittest.TestCase):
             'baz': (dict, list, ''),
         })
 
-        self.assertEqual(test.keys(), [])
+        self.assertEqual(list(test.keys()), [])
 
         with self.assertRaises(ValueError):
             test.update(bar=True, foo={})
 
-        self.assertEqual(test.keys(), [])
+        self.assertEqual(list(test.keys()), [])
 
         test.update(bar=True, foo=1)
 
@@ -124,7 +124,7 @@ class TestContext(unittest.TestCase):
         # Adding the first source makes it the main and current path.
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, foo)
-        self.assertEqual(test.all_paths, set([foo]))
+        self.assertEqual(test.all_paths, {foo})
         self.assertEqual(test.source_stack, [foo])
 
         bar = os.path.abspath('bar')
@@ -133,7 +133,7 @@ class TestContext(unittest.TestCase):
         # Adding the second source makes leaves main and current paths alone.
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, foo)
-        self.assertEqual(test.all_paths, set([bar, foo]))
+        self.assertEqual(test.all_paths, {bar, foo})
         self.assertEqual(test.source_stack, [foo])
 
         qux = os.path.abspath('qux')
@@ -142,14 +142,14 @@ class TestContext(unittest.TestCase):
         # Pushing a source makes it the current path
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, qux)
-        self.assertEqual(test.all_paths, set([bar, foo, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, qux})
         self.assertEqual(test.source_stack, [foo, qux])
 
         hoge = os.path.abspath('hoge')
         test.push_source(hoge)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, hoge)
-        self.assertEqual(test.all_paths, set([bar, foo, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, hoge, qux})
         self.assertEqual(test.source_stack, [foo, qux, hoge])
 
         fuga = os.path.abspath('fuga')
@@ -158,14 +158,14 @@ class TestContext(unittest.TestCase):
         test.add_source(fuga)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, hoge)
-        self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, fuga, hoge, qux})
         self.assertEqual(test.source_stack, [foo, qux, hoge])
 
         # Adding a source twice doesn't change anything
         test.add_source(qux)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, hoge)
-        self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, fuga, hoge, qux})
         self.assertEqual(test.source_stack, [foo, qux, hoge])
 
         last = test.pop_source()
@@ -174,14 +174,14 @@ class TestContext(unittest.TestCase):
         self.assertEqual(last, hoge)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, qux)
-        self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, fuga, hoge, qux})
         self.assertEqual(test.source_stack, [foo, qux])
 
         last = test.pop_source()
         self.assertEqual(last, qux)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, foo)
-        self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, fuga, hoge, qux})
         self.assertEqual(test.source_stack, [foo])
 
         # Popping the main path is allowed.
@@ -189,7 +189,7 @@ class TestContext(unittest.TestCase):
         self.assertEqual(last, foo)
         self.assertEqual(test.main_path, foo)
         self.assertIsNone(test.current_path)
-        self.assertEqual(test.all_paths, set([bar, foo, fuga, hoge, qux]))
+        self.assertEqual(test.all_paths, {bar, foo, fuga, hoge, qux})
         self.assertEqual(test.source_stack, [])
 
         # Popping past the main path asserts.
@@ -210,11 +210,11 @@ class TestContext(unittest.TestCase):
         self.assertEqual(last, foo)
         self.assertEqual(test.main_path, foo)
         self.assertEqual(test.current_path, foo)
-        self.assertEqual(test.all_paths, set([bar, foo]))
+        self.assertEqual(test.all_paths, {bar, foo})
         self.assertEqual(test.source_stack, [foo, bar, bar, foo])
 
     def test_context_dirs(self):
-        class Config(object): pass
+        class Config: pass
         config = Config()
         config.topsrcdir = mozpath.abspath(os.curdir)
         config.topobjdir = mozpath.abspath('obj')
@@ -277,7 +277,7 @@ class TestSymbols(unittest.TestCase):
 class TestPaths(unittest.TestCase):
     @classmethod
     def setUpClass(cls):
-        class Config(object): pass
+        class Config: pass
         cls.config = config = Config()
         config.topsrcdir = mozpath.abspath(os.curdir)
         config.topobjdir = mozpath.abspath('obj')
@@ -631,7 +631,7 @@ class TestPaths(unittest.TestCase):
 class TestTypedRecord(unittest.TestCase):
 
     def test_fields(self):
-        T = ContextDerivedTypedRecord(('field1', unicode),
+        T = ContextDerivedTypedRecord(('field1', str),
                                       ('field2', list))
         inst = T(None)
         self.assertEqual(inst.field1, '')
@@ -647,7 +647,7 @@ class TestTypedRecord(unittest.TestCase):
             inst.field3 = []
 
     def test_coercion(self):
-        T = ContextDerivedTypedRecord(('field1', unicode),
+        T = ContextDerivedTypedRecord(('field1', str),
                                       ('field2', list))
         inst = T(None)
         inst.field1 = 3
@@ -673,45 +673,45 @@ class TestFiles(unittest.TestCase):
     def test_single_bug_component(self):
         c = Context({})
         f = Files(c, pattern='**')
-        f['BUG_COMPONENT'] = (u'Product1', u'Component1')
+        f['BUG_COMPONENT'] = ('Product1', 'Component1')
 
         files = {'moz.build': f}
         self.assertEqual(Files.aggregate(files), {
-            'bug_component_counts': [((u'Product1', u'Component1'), 1)],
-            'recommended_bug_component': (u'Product1', u'Component1'),
+            'bug_component_counts': [(('Product1', 'Component1'), 1)],
+            'recommended_bug_component': ('Product1', 'Component1'),
         })
 
     def test_multiple_bug_components(self):
         c = Context({})
         f1 = Files(c, pattern='**')
-        f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
+        f1['BUG_COMPONENT'] = ('Product1', 'Component1')
 
         f2 = Files(c, pattern='**')
-        f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
+        f2['BUG_COMPONENT'] = ('Product2', 'Component2')
 
         files = {'a': f1, 'b': f2, 'c': f1}
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [
-                ((u'Product1', u'Component1'), 2),
-                ((u'Product2', u'Component2'), 1),
+                (('Product1', 'Component1'), 2),
+                (('Product2', 'Component2'), 1),
             ],
-            'recommended_bug_component': (u'Product1', u'Component1'),
+            'recommended_bug_component': ('Product1', 'Component1'),
         })
 
     def test_no_recommended_bug_component(self):
         """If there is no clear count winner, we don't recommend a bug component."""
         c = Context({})
         f1 = Files(c, pattern='**')
-        f1['BUG_COMPONENT'] = (u'Product1', u'Component1')
+        f1['BUG_COMPONENT'] = ('Product1', 'Component1')
 
         f2 = Files(c, pattern='**')
-        f2['BUG_COMPONENT'] = (u'Product2', u'Component2')
+        f2['BUG_COMPONENT'] = ('Product2', 'Component2')
 
         files = {'a': f1, 'b': f2}
         self.assertEqual(Files.aggregate(files), {
             'bug_component_counts': [
-                ((u'Product1', u'Component1'), 1),
-                ((u'Product2', u'Component2'), 1),
+                (('Product1', 'Component1'), 1),
+                (('Product2', 'Component2'), 1),
             ],
             'recommended_bug_component': None,
         })
diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
index e1e3fa5ce2..11bd3316b4 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import unittest
@@ -125,8 +124,8 @@ class TestEmitterBasic(unittest.TestCase):
         for o in objs:
             self.assertIsInstance(o, DirectoryTraversal)
 
-        reldirs = set([o.relativedir for o in objs])
-        self.assertEqual(reldirs, set(['', 'regular']))
+        reldirs = {o.relativedir for o in objs}
+        self.assertEqual(reldirs, {'', 'regular'})
 
         for o in objs:
             reldir = o.relativedir
@@ -143,8 +142,8 @@ class TestEmitterBasic(unittest.TestCase):
         for o in objs:
             self.assertIsInstance(o, DirectoryTraversal)
 
-        reldirs = set([o.relativedir for o in objs])
-        self.assertEqual(reldirs, set(['', 'regular', 'test']))
+        reldirs = {o.relativedir for o in objs}
+        self.assertEqual(reldirs, {'', 'regular', 'test'})
 
         for o in objs:
             reldir = o.relativedir
@@ -204,7 +203,7 @@ class TestEmitterBasic(unittest.TestCase):
     def test_use_yasm(self):
         # When yasm is not available, this should raise.
         reader = self.reader('use-yasm')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'yasm is not available'):
             self.read_topsrcdir(reader)
 
@@ -267,25 +266,25 @@ class TestEmitterBasic(unittest.TestCase):
         o = objs[0]
         self.assertIsInstance(o, GeneratedFile)
         self.assertEqual(o.outputs, ('bar.c',))
-        self.assertRegexpMatches(o.script, 'script.py$')
+        self.assertRegex(o.script, 'script.py$')
         self.assertEqual(o.method, 'make_bar')
         self.assertEqual(o.inputs, [])
 
     def test_generated_files_no_script(self):
         reader = self.reader('generated-files-no-script')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'Script for generating bar.c does not exist'):
             self.read_topsrcdir(reader)
 
     def test_generated_files_no_inputs(self):
         reader = self.reader('generated-files-no-inputs')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'Input for generating foo.c does not exist'):
             self.read_topsrcdir(reader)
 
     def test_generated_files_no_python_script(self):
         reader = self.reader('generated-files-no-python-script')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'Script for generating bar.c does not end in .py'):
             self.read_topsrcdir(reader)
 
@@ -314,7 +313,7 @@ class TestEmitterBasic(unittest.TestCase):
         Missing files in EXPORTS is an error.
         '''
         reader = self.reader('exports-missing')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
              'File listed in EXPORTS does not exist:'):
             self.read_topsrcdir(reader)
 
@@ -323,7 +322,7 @@ class TestEmitterBasic(unittest.TestCase):
         An objdir file in EXPORTS that is not in GENERATED_FILES is an error.
         '''
         reader = self.reader('exports-missing-generated')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
              'Objdir file listed in EXPORTS not in GENERATED_FILES:'):
             self.read_topsrcdir(reader)
 
@@ -360,7 +359,7 @@ class TestEmitterBasic(unittest.TestCase):
 
     def test_test_harness_files_root(self):
         reader = self.reader('test-harness-files-root')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'Cannot install files to the root of TEST_HARNESS_FILES'):
             self.read_topsrcdir(reader)
 
@@ -413,14 +412,14 @@ class TestEmitterBasic(unittest.TestCase):
         """A missing manifest file should result in an error."""
         reader = self.reader('test-manifest-missing-manifest')
 
-        with self.assertRaisesRegexp(BuildReaderError, 'IOError: Missing files'):
+        with self.assertRaisesRegex(BuildReaderError, 'IOError: Missing files'):
             self.read_topsrcdir(reader)
 
     def test_empty_test_manifest_rejected(self):
         """A test manifest without any entries is rejected."""
         reader = self.reader('test-manifest-empty')
 
-        with self.assertRaisesRegexp(SandboxValidationError, 'Empty test manifest'):
+        with self.assertRaisesRegex(SandboxValidationError, 'Empty test manifest'):
             self.read_topsrcdir(reader)
 
 
@@ -428,7 +427,7 @@ class TestEmitterBasic(unittest.TestCase):
         """A test manifest with no tests but support-files is not supported."""
         reader = self.reader('test-manifest-just-support')
 
-        with self.assertRaisesRegexp(SandboxValidationError, 'Empty test manifest'):
+        with self.assertRaisesRegex(SandboxValidationError, 'Empty test manifest'):
             self.read_topsrcdir(reader)
 
     def test_test_manifest_dupe_support_files(self):
@@ -437,7 +436,7 @@ class TestEmitterBasic(unittest.TestCase):
         """
         reader = self.reader('test-manifest-dupes')
 
-        with self.assertRaisesRegexp(SandboxValidationError, 'bar.js appears multiple times '
+        with self.assertRaisesRegex(SandboxValidationError, 'bar.js appears multiple times '
             'in a test manifest under a support-files field, please omit the duplicate entry.'):
             self.read_topsrcdir(reader)
 
@@ -481,7 +480,7 @@ class TestEmitterBasic(unittest.TestCase):
         """A non-existent shared support file reference produces an error."""
         reader = self.reader('test-manifest-shared-missing')
 
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
                                      'entry in support-files not present in the srcdir'):
             self.read_topsrcdir(reader)
 
@@ -541,7 +540,7 @@ class TestEmitterBasic(unittest.TestCase):
     def test_python_unit_test_missing(self):
         """Missing files in PYTHON_UNIT_TESTS should raise."""
         reader = self.reader('test-python-unit-test-missing')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'Path specified in PYTHON_UNIT_TESTS does not exist:'):
             self.read_topsrcdir(reader)
 
@@ -630,8 +629,8 @@ class TestEmitterBasic(unittest.TestCase):
             self.assertEqual(o.flavor, m['flavor'])
             self.assertEqual(o.dupe_manifest, m.get('dupe', False))
 
-            external_normalized = set(mozpath.basename(p) for p in
-                    o.external_installs)
+            external_normalized = {mozpath.basename(p) for p in
+                    o.external_installs}
             self.assertEqual(external_normalized, m.get('external', set()))
 
             self.assertEqual(len(o.installs), len(m['installs']))
@@ -648,7 +647,7 @@ class TestEmitterBasic(unittest.TestCase):
     def test_test_manifest_unmatched_generated(self):
         reader = self.reader('test-manifest-unmatched-generated')
 
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'entry in generated-files not present elsewhere'):
             self.read_topsrcdir(reader),
 
@@ -672,7 +671,7 @@ class TestEmitterBasic(unittest.TestCase):
         """Missing test files should result in error."""
         reader = self.reader('test-manifest-missing-test-file')
 
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'lists test that does not exist: test_missing.html'):
             self.read_topsrcdir(reader)
 
@@ -680,7 +679,7 @@ class TestEmitterBasic(unittest.TestCase):
         """Missing test files should result in error, even when the test list is not filtered."""
         reader = self.reader('test-manifest-missing-test-file-unfiltered')
 
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
             'lists test that does not exist: missing.js'):
             self.read_topsrcdir(reader)
 
@@ -692,9 +691,9 @@ class TestEmitterBasic(unittest.TestCase):
         nonstatic_ipdls = []
         for o in objs:
             if isinstance(o, IPDLFile):
-                ipdls.append('%s/%s' % (o.relativedir, o.basename))
+                ipdls.append('{}/{}'.format(o.relativedir, o.basename))
             elif isinstance(o, PreprocessedIPDLFile):
-                nonstatic_ipdls.append('%s/%s' % (o.relativedir, o.basename))
+                nonstatic_ipdls.append('{}/{}'.format(o.relativedir, o.basename))
 
         expected = [
             'bar/bar.ipdl',
@@ -802,20 +801,20 @@ class TestEmitterBasic(unittest.TestCase):
             self.assertIsInstance(obj.path, Path)
 
     def test_jar_manifests_multiple_files(self):
-        with self.assertRaisesRegexp(SandboxValidationError, 'limited to one value'):
+        with self.assertRaisesRegex(SandboxValidationError, 'limited to one value'):
             reader = self.reader('jar-manifests-multiple-files')
             self.read_topsrcdir(reader)
 
     def test_xpidl_module_no_sources(self):
         """XPIDL_MODULE without XPIDL_SOURCES should be rejected."""
-        with self.assertRaisesRegexp(SandboxValidationError, 'XPIDL_MODULE '
+        with self.assertRaisesRegex(SandboxValidationError, 'XPIDL_MODULE '
             'cannot be defined'):
             reader = self.reader('xpidl-module-no-sources')
             self.read_topsrcdir(reader)
 
     def test_missing_local_includes(self):
         """LOCAL_INCLUDES containing non-existent directories should be rejected."""
-        with self.assertRaisesRegexp(SandboxValidationError, 'Path specified in '
+        with self.assertRaisesRegex(SandboxValidationError, 'Path specified in '
             'LOCAL_INCLUDES does not exist'):
             reader = self.reader('missing-local-includes')
             self.read_topsrcdir(reader)
@@ -1013,11 +1012,11 @@ class TestEmitterBasic(unittest.TestCase):
 
             expected = {'install.rdf', 'main.js'}
             for f in files:
-                self.assertTrue(unicode(f) in expected)
+                self.assertTrue(str(f) in expected)
 
     def test_missing_final_target_pp_files(self):
         """Test that FINAL_TARGET_PP_FILES with missing files throws errors."""
-        with self.assertRaisesRegexp(SandboxValidationError, 'File listed in '
+        with self.assertRaisesRegex(SandboxValidationError, 'File listed in '
             'FINAL_TARGET_PP_FILES does not exist'):
             reader = self.reader('dist-files-missing')
             self.read_topsrcdir(reader)
@@ -1025,7 +1024,7 @@ class TestEmitterBasic(unittest.TestCase):
     def test_final_target_pp_files_non_srcdir(self):
         '''Test that non-srcdir paths in FINAL_TARGET_PP_FILES throws errors.'''
         reader = self.reader('final-target-pp-files-non-srcdir')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
              'Only source directory paths allowed in FINAL_TARGET_PP_FILES:'):
             self.read_topsrcdir(reader)
 
@@ -1043,7 +1042,7 @@ class TestEmitterBasic(unittest.TestCase):
             mozpath.join(reader.config.topobjdir, 'dir2'),
             '/dir3',
         ]
-        self.assertEquals([p.full_path for p in objs[0].paths], expected)
+        self.assertEqual([p.full_path for p in objs[0].paths], expected)
 
     def test_binary_components(self):
         """Test that IS_COMPONENT/NO_COMPONENTS_MANIFEST work properly."""
@@ -1099,7 +1098,7 @@ class TestEmitterBasic(unittest.TestCase):
         from GENERATED_FILES is an error.
         """
         reader = self.reader('test-symbols-file-objdir-missing-generated')
-        with self.assertRaisesRegexp(SandboxValidationError,
+        with self.assertRaisesRegex(SandboxValidationError,
              'Objdir file specified in SYMBOLS_FILE not in GENERATED_FILES:'):
             self.read_topsrcdir(reader)
 
diff --git a/python/mozbuild/mozbuild/test/frontend/test_namespaces.py b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py
index 71cc634e1b..1280d53741 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_namespaces.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import unittest
 
@@ -22,14 +21,14 @@ from mozbuild.util import (
 )
 
 
-class Fuga(object):
+class Fuga:
     def __init__(self, value):
         self.value = value
 
 
 class Piyo(ContextDerivedValue):
     def __init__(self, context, value):
-        if not isinstance(value, unicode):
+        if not isinstance(value, str):
             raise ValueError
         self.context = context
         self.value = value
@@ -48,9 +47,9 @@ class Piyo(ContextDerivedValue):
 
 
 VARIABLES = {
-    'HOGE': (unicode, unicode, None),
-    'FUGA': (Fuga, unicode, None),
-    'PIYO': (Piyo, unicode, None),
+    'HOGE': (str, str, None),
+    'FUGA': (Fuga, str, None),
+    'PIYO': (Piyo, str, None),
     'HOGERA': (ContextDerivedTypedList(Piyo, StrictOrderingOnAppendList),
         list, None),
     'HOGEHOGE': (ContextDerivedTypedListWithItems(
@@ -104,7 +103,7 @@ class TestContext(unittest.TestCase):
         self.assertEqual(e[1], 'set_type')
         self.assertEqual(e[2], 'HOGE')
         self.assertEqual(e[3], True)
-        self.assertEqual(e[4], unicode)
+        self.assertEqual(e[4], str)
 
     def test_key_checking(self):
         # Checking for existence of a key should not populate the key if it
@@ -127,7 +126,7 @@ class TestContext(unittest.TestCase):
         self.assertEqual(e[1], 'set_type')
         self.assertEqual(e[2], 'FUGA')
         self.assertEqual(e[3], False)
-        self.assertEqual(e[4], unicode)
+        self.assertEqual(e[4], str)
 
         ns['FUGA'] = 'fuga'
         self.assertIsInstance(ns['FUGA'], Fuga)
@@ -150,7 +149,7 @@ class TestContext(unittest.TestCase):
         self.assertEqual(e[1], 'set_type')
         self.assertEqual(e[2], 'PIYO')
         self.assertEqual(e[3], False)
-        self.assertEqual(e[4], unicode)
+        self.assertEqual(e[4], str)
 
         ns['PIYO'] = 'piyo'
         self.assertIsInstance(ns['PIYO'], Piyo)
diff --git a/python/mozbuild/mozbuild/test/frontend/test_reader.py b/python/mozbuild/mozbuild/test/frontend/test_reader.py
index 7c2aed9dfc..690a84b771 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_reader.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_reader.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import sys
@@ -21,10 +20,7 @@ from mozbuild.test.common import MockConfig
 import mozpack.path as mozpath
 
 
-if sys.version_info.major == 2:
-    text_type = 'unicode'
-else:
-    text_type = 'str'
+text_type = 'str'
 
 data_path = mozpath.abspath(mozpath.dirname(__file__))
 data_path = mozpath.join(data_path, 'data')
@@ -412,10 +408,10 @@ class TestBuildReader(unittest.TestCase):
         reader = self.reader('files-test-metadata')
 
         expected = {
-            'simple/src/module.jsm': set(['simple/tests/test_general.html',
-                                          'simple/browser/**.js']),
-            'simple/base.cpp': set(['simple/tests/*',
-                                    'default/tests/xpcshell/test_default_mod.js']),
+            'simple/src/module.jsm': {'simple/tests/test_general.html',
+                                          'simple/browser/**.js'},
+            'simple/base.cpp': {'simple/tests/*',
+                                    'default/tests/xpcshell/test_default_mod.js'},
         }
 
         v = reader.files_info([
@@ -434,8 +430,8 @@ class TestBuildReader(unittest.TestCase):
         ])
 
         expected = {
-            'default/module.js': set(['default/tests/xpcshell/**',
-                                      'default/tests/reftests/**']),
+            'default/module.js': {'default/tests/xpcshell/**',
+                                      'default/tests/reftests/**'},
         }
 
         for path, pattern_set in expected.items():
@@ -450,8 +446,8 @@ class TestBuildReader(unittest.TestCase):
         ])
 
         expected_patterns = {
-            'tagged/src/submodule/foo.js': set([]),
-            'tagged/src/bar.jsm': set(['tagged/**.js']),
+            'tagged/src/submodule/foo.js': set(),
+            'tagged/src/bar.jsm': {'tagged/**.js'},
         }
 
         for path, pattern_set in expected_patterns.items():
@@ -459,16 +455,16 @@ class TestBuildReader(unittest.TestCase):
                              expected_patterns[path])
 
         expected_tags = {
-            'tagged/src/submodule/foo.js': set(['submodule']),
-            'tagged/src/bar.jsm': set([]),
+            'tagged/src/submodule/foo.js': {'submodule'},
+            'tagged/src/bar.jsm': set(),
         }
         for path, pattern_set in expected_tags.items():
             self.assertEqual(v[path].test_tags,
                              expected_tags[path])
 
         expected_flavors = {
-            'tagged/src/bar.jsm': set(['browser-chrome']),
-            'tagged/src/submodule/foo.js': set([]),
+            'tagged/src/bar.jsm': {'browser-chrome'},
+            'tagged/src/submodule/foo.js': set(),
         }
         for path, pattern_set in expected_flavors.items():
             self.assertEqual(v[path].test_flavors,
diff --git a/python/mozbuild/mozbuild/test/frontend/test_sandbox.py b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
index d24c5d9ea6..4236e84750 100644
--- a/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_sandbox.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import shutil
@@ -30,7 +29,7 @@ from mozbuild.frontend.context import (
 )
 
 from mozbuild.test.common import MockConfig
-from types import StringTypes
+StringTypes = (str,)
 
 import mozpack.path as mozpath
 
@@ -52,7 +51,7 @@ class TestSandbox(unittest.TestCase):
 
         self.assertNotIn('foo', context)
         self.assertEqual(context.main_path, mozpath.abspath('foo.py'))
-        self.assertEqual(context.all_paths, set([mozpath.abspath('foo.py')]))
+        self.assertEqual(context.all_paths, {mozpath.abspath('foo.py')})
 
     def test_exec_compile_error(self):
         sandbox = self.sandbox()
@@ -137,10 +136,10 @@ class TestedSandbox(MozbuildSandbox):
         return SourcePath(self._context, path)
 
     def exec_file(self, path):
-        super(TestedSandbox, self).exec_file(self.normalize_path(path))
+        super().exec_file(self.normalize_path(path))
 
     def exec_source(self, source, path=''):
-        super(TestedSandbox, self).exec_source(source,
+        super().exec_source(source,
             self.normalize_path(path) if path else '')
 
 
@@ -345,7 +344,7 @@ class TestMozbuildSandbox(unittest.TestCase):
         sandbox = MozbuildSandbox(Context(VARIABLES, config))
 
         self.assertEqual(sandbox['CONFIG']['BAD_UTF8'],
-            u'\ufffd\ufffd\ufffd\ufffd:')
+            '\ufffd\ufffd\ufffd\ufffd:')
 
     def test_invalid_exports_set_base(self):
         sandbox = self.sandbox()
@@ -525,7 +524,7 @@ def Template():
             source = 'a = foo(1, 2)'
             sandbox.exec_source(source, 'foo.mozbuild')
 
-            self.assertEquals(sandbox['a'], (Foo, int))
+            self.assertEqual(sandbox['a'], (Foo, int))
         finally:
             del FUNCTIONS['foo']
 
diff --git a/python/mozbuild/mozbuild/test/test_base.py b/python/mozbuild/mozbuild/test/test_base.py
index 87f0db85bf..1696cfbf4b 100644
--- a/python/mozbuild/mozbuild/test/test_base.py
+++ b/python/mozbuild/mozbuild/test/test_base.py
@@ -2,8 +2,8 @@
 # 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 unicode_literals
 
+from __future__ import print_function
 import json
 import os
 import shutil
@@ -91,9 +91,9 @@ class TestMozbuildObject(unittest.TestCase):
         d = os.path.realpath(tempfile.mkdtemp())
         try:
             mozconfig = os.path.join(d, 'mozconfig')
-            with open(mozconfig, 'wt') as fh:
+            with open(mozconfig, 'w') as fh:
                 fh.write('mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/foo/@CONFIG_GUESS@')
-            print('Wrote mozconfig %s' % mozconfig)
+            print(('Wrote mozconfig %s' % mozconfig))
 
             topobjdir = os.path.join(d, 'foo', guess)
             os.makedirs(topobjdir)
@@ -105,7 +105,7 @@ class TestMozbuildObject(unittest.TestCase):
                 'config.guess',), guess_path)
 
             mozinfo = os.path.join(topobjdir, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump(dict(
                     topsrcdir=d,
                     mozconfig=mozconfig,
@@ -127,14 +127,14 @@ class TestMozbuildObject(unittest.TestCase):
         d = os.path.realpath(tempfile.mkdtemp())
         try:
             mozconfig = os.path.join(d, 'mozconfig')
-            with open(mozconfig, 'wt') as fh:
+            with open(mozconfig, 'w') as fh:
                 fh.write('mk_add_options MOZ_OBJDIR=./objdir')
 
             topobjdir = mozpath.join(d, 'objdir')
             os.mkdir(topobjdir)
 
             mozinfo = os.path.join(topobjdir, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump(dict(
                     topsrcdir=d,
                     mozconfig=mozconfig,
@@ -166,11 +166,11 @@ class TestMozbuildObject(unittest.TestCase):
             os.symlink(topobjdir_real, topobjdir_link)
 
             mozconfig = os.path.join(d, 'mozconfig')
-            with open(mozconfig, 'wt') as fh:
+            with open(mozconfig, 'w') as fh:
                 fh.write('mk_add_options MOZ_OBJDIR=%s' % topobjdir_link)
 
             mozinfo = os.path.join(topobjdir_real, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump(dict(
                     topsrcdir=d,
                     mozconfig=mozconfig,
@@ -201,14 +201,14 @@ class TestMozbuildObject(unittest.TestCase):
             os.makedirs(topsrcdir)
 
             mozinfo = os.path.join(topobjdir, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump(dict(
                     topsrcdir=topsrcdir,
                 ), fh)
 
             os.chdir(topobjdir)
 
-            class MockMachContext(object):
+            class MockMachContext:
                 pass
 
             context = MockMachContext()
@@ -235,7 +235,7 @@ class TestMozbuildObject(unittest.TestCase):
             # The easiest way to do this is to create a mozinfo.json with data
             # that will never happen.
             mozinfo = os.path.join(d, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump({'topsrcdir': d}, fh)
 
             os.chdir(d)
@@ -262,11 +262,11 @@ class TestMozbuildObject(unittest.TestCase):
             os.makedirs(topsrcdir)
 
             mozconfig = os.path.join(d, 'mozconfig')
-            with open(mozconfig, 'wt') as fh:
+            with open(mozconfig, 'w') as fh:
                 fh.write('mk_add_options MOZ_OBJDIR=%s' % real_topobjdir)
 
             mozinfo = os.path.join(topobjdir, 'mozinfo.json')
-            with open(mozinfo, 'wt') as fh:
+            with open(mozinfo, 'w') as fh:
                 json.dump(dict(
                     topsrcdir=topsrcdir,
                     mozconfig=mozconfig,
@@ -274,7 +274,7 @@ class TestMozbuildObject(unittest.TestCase):
 
             os.chdir(topobjdir)
 
-            class MockMachContext(object):
+            class MockMachContext:
                 pass
 
             context = MockMachContext()
diff --git a/python/mozbuild/mozbuild/test/test_containers.py b/python/mozbuild/mozbuild/test/test_containers.py
index 3d46f86a90..116eb9008c 100644
--- a/python/mozbuild/mozbuild/test/test_containers.py
+++ b/python/mozbuild/mozbuild/test/test_containers.py
@@ -152,7 +152,7 @@ class TestOrderedDefaultDict(unittest.TestCase):
 
         self.assertEqual(test['foo'], 1)
 
-        self.assertEqual(test.keys(), ['foo', 'bar' ])
+        self.assertEqual(list(test.keys()), ['foo', 'bar' ])
 
     def test_defaults(self):
         test = OrderedDefaultDict(bool, {'foo': 1 })
@@ -161,7 +161,7 @@ class TestOrderedDefaultDict(unittest.TestCase):
 
         self.assertEqual(test['qux'], False)
 
-        self.assertEqual(test.keys(), ['foo', 'qux' ])
+        self.assertEqual(list(test.keys()), ['foo', 'qux' ])
 
 
 class TestKeyedDefaultDict(unittest.TestCase):
diff --git a/python/mozbuild/mozbuild/test/test_dotproperties.py b/python/mozbuild/mozbuild/test/test_dotproperties.py
index a03f85b0d1..353ca4c551 100644
--- a/python/mozbuild/mozbuild/test/test_dotproperties.py
+++ b/python/mozbuild/mozbuild/test/test_dotproperties.py
@@ -1,7 +1,3 @@
-# -*- coding: utf-8 -*-
-
-from __future__ import unicode_literals
-
 import os
 import unittest
 
diff --git a/python/mozbuild/mozbuild/test/test_expression.py b/python/mozbuild/mozbuild/test/test_expression.py
index fb3c45894c..97b1191a99 100644
--- a/python/mozbuild/mozbuild/test/test_expression.py
+++ b/python/mozbuild/mozbuild/test/test_expression.py
@@ -25,8 +25,8 @@ class TestContext(unittest.TestCase):
 
   def test_in(self):
     """test 'var in context' to not fall for fallback"""
-    self.assert_('FAIL' in self.c)
-    self.assert_('PASS' not in self.c)
+    self.assertTrue('FAIL' in self.c)
+    self.assertTrue('PASS' not in self.c)
 
 class TestExpression(unittest.TestCase):
   """
@@ -48,16 +48,16 @@ class TestExpression(unittest.TestCase):
 
   def test_not(self):
     """Test for the ! operator"""
-    self.assert_(Expression('!0').evaluate(self.c))
-    self.assert_(not Expression('!1').evaluate(self.c))
+    self.assertTrue(Expression('!0').evaluate(self.c))
+    self.assertTrue(not Expression('!1').evaluate(self.c))
 
   def test_equals(self):
     """ Test for the == operator"""
-    self.assert_(Expression('FAIL == PASS').evaluate(self.c))
+    self.assertTrue(Expression('FAIL == PASS').evaluate(self.c))
 
   def test_notequals(self):
     """ Test for the != operator"""
-    self.assert_(Expression('FAIL != 1').evaluate(self.c))
+    self.assertTrue(Expression('FAIL != 1').evaluate(self.c))
 
   def test_logical_and(self):
     """ Test for the && operator"""
diff --git a/python/mozbuild/mozbuild/test/test_jarmaker.py b/python/mozbuild/mozbuild/test/test_jarmaker.py
index a4d4156a72..87f9ba9981 100644
--- a/python/mozbuild/mozbuild/test/test_jarmaker.py
+++ b/python/mozbuild/mozbuild/test/test_jarmaker.py
@@ -117,12 +117,12 @@ class _TreeDiff(dircmp):
     """Helper to report rich results on difference between two directories.
     """
     def _fillDiff(self, dc, rv, basepath="{0}"):
-        rv['right_only'] += map(lambda l: basepath.format(l), dc.right_only)
-        rv['left_only'] += map(lambda l: basepath.format(l), dc.left_only)
-        rv['diff_files'] += map(lambda l: basepath.format(l), dc.diff_files)
-        rv['funny'] += map(lambda l: basepath.format(l), dc.common_funny)
-        rv['funny'] += map(lambda l: basepath.format(l), dc.funny_files)
-        for subdir, _dc in dc.subdirs.iteritems():
+        rv['right_only'] += [basepath.format(l) for l in dc.right_only]
+        rv['left_only'] += [basepath.format(l) for l in dc.left_only]
+        rv['diff_files'] += [basepath.format(l) for l in dc.diff_files]
+        rv['funny'] += [basepath.format(l) for l in dc.common_funny]
+        rv['funny'] += [basepath.format(l) for l in dc.funny_files]
+        for subdir, _dc in dc.subdirs.items():
             self._fillDiff(_dc, rv, basepath.format(subdir + "/{0}"))
     def allResults(self, left, right):
         rv = {'right_only':[], 'left_only':[],
@@ -130,15 +130,15 @@ class _TreeDiff(dircmp):
         self._fillDiff(self, rv)
         chunks = []
         if rv['right_only']:
-            chunks.append('{0} only in {1}'.format(', '.join(rv['right_only']),
+            chunks.append('{} only in {}'.format(', '.join(rv['right_only']),
                                                    right))
         if rv['left_only']:
-            chunks.append('{0} only in {1}'.format(', '.join(rv['left_only']),
+            chunks.append('{} only in {}'.format(', '.join(rv['left_only']),
                                                    left))
         if rv['diff_files']:
-            chunks.append('{0} differ'.format(', '.join(rv['diff_files'])))
+            chunks.append('{} differ'.format(', '.join(rv['diff_files'])))
         if rv['funny']:
-            chunks.append("{0} don't compare".format(', '.join(rv['funny'])))
+            chunks.append("{} don't compare".format(', '.join(rv['funny'])))
         return '; '.join(chunks)
 
 class TestJarMaker(unittest.TestCase):
@@ -159,7 +159,7 @@ class TestJarMaker(unittest.TestCase):
 
     def tearDown(self):
         if self.debug:
-            print(self.tmpdir)
+            print((self.tmpdir))
         elif sys.platform != "win32":
             # can't clean up on windows
             rmtree(self.tmpdir)
@@ -243,7 +243,7 @@ class TestJarMaker(unittest.TestCase):
         srcbar = os.path.join(self.srcdir, 'bar')
         destfoo = os.path.join(self.builddir, 'chrome', 'test', 'dir', 'foo')
         self.assertTrue(is_symlink_to(destfoo, srcbar),
-                        "{0} is not a symlink to {1}".format(destfoo, srcbar))
+                        "{} is not a symlink to {}".format(destfoo, srcbar))
 
     def _create_wildcard_setup(self):
         # create src content
@@ -295,12 +295,12 @@ class TestJarMaker(unittest.TestCase):
             ('hoge', 'foo', '2'): ('qux', 'foo', '2'),
             ('hoge', 'baz'): ('qux', 'baz'),
         }
-        for dest, src in expected_symlinks.iteritems():
+        for dest, src in expected_symlinks.items():
             srcpath = os.path.join(self.srcdir, *src)
             destpath = os.path.join(self.builddir, 'chrome', 'test', 'dir',
                                     *dest)
             self.assertTrue(is_symlink_to(destpath, srcpath),
-                            "{0} is not a symlink to {1}".format(destpath,
+                            "{} is not a symlink to {}".format(destpath,
                                                                  srcpath))
 
 
@@ -317,7 +317,7 @@ class Test_relativesrcdir(unittest.TestCase):
     def test_en_US(self):
         jm = self.jm
         jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
-        self.assertEquals(jm.localedirs,
+        self.assertEqual(jm.localedirs,
                           [
                             os.path.join(os.path.abspath('/TOPSOURCEDIR'),
                                          'browser/locales', 'en-US')
@@ -326,13 +326,13 @@ class Test_relativesrcdir(unittest.TestCase):
         jm = self.jm
         jm.l10nbase = '/L10N_BASE'
         jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
-        self.assertEquals(jm.localedirs, [os.path.join('/L10N_BASE', 'browser')])
+        self.assertEqual(jm.localedirs, [os.path.join('/L10N_BASE', 'browser')])
     def test_l10n_merge(self):
         jm = self.jm
         jm.l10nbase = '/L10N_BASE'
         jm.l10nmerge = '/L10N_MERGE'
         jm.makeJar(self.fake_empty_file, '/NO_OUTPUT_REQUIRED')
-        self.assertEquals(jm.localedirs,
+        self.assertEqual(jm.localedirs,
                           [os.path.join('/L10N_MERGE', 'browser'),
                            os.path.join('/L10N_BASE', 'browser'),
                            os.path.join(os.path.abspath('/TOPSOURCEDIR'),
@@ -346,7 +346,7 @@ relativesrcdir dom/locales:
 ''')
         jarcontents.name = 'override.mn'
         jm.makeJar(jarcontents, '/NO_OUTPUT_REQUIRED')
-        self.assertEquals(jm.localedirs,
+        self.assertEqual(jm.localedirs,
                           [
                             os.path.join(os.path.abspath('/TOPSOURCEDIR'),
                                          'dom/locales', 'en-US')
@@ -360,7 +360,7 @@ relativesrcdir dom/locales:
 ''')
         jarcontents.name = 'override.mn'
         jm.makeJar(jarcontents, '/NO_OUTPUT_REQUIRED')
-        self.assertEquals(jm.localedirs, [os.path.join('/L10N_BASE', 'dom')])
+        self.assertEqual(jm.localedirs, [os.path.join('/L10N_BASE', 'dom')])
 
 
 if __name__ == '__main__':
diff --git a/python/mozbuild/mozbuild/test/test_line_endings.py b/python/mozbuild/mozbuild/test/test_line_endings.py
index 565abc8c93..2429c96e1c 100644
--- a/python/mozbuild/mozbuild/test/test_line_endings.py
+++ b/python/mozbuild/mozbuild/test/test_line_endings.py
@@ -30,17 +30,17 @@ class TestLineEndings(unittest.TestCase):
   def testMac(self):
     self.createFile(['\x0D']*3)
     self.pp.do_include(self.tempnam)
-    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+    self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
 
   def testUnix(self):
     self.createFile(['\x0A']*3)
     self.pp.do_include(self.tempnam)
-    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+    self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
 
   def testWindows(self):
     self.createFile(['\x0D\x0A']*3)
     self.pp.do_include(self.tempnam)
-    self.assertEquals(self.pp.out.getvalue(), 'a\nb\nc\n')
+    self.assertEqual(self.pp.out.getvalue(), 'a\nb\nc\n')
 
 if __name__ == '__main__':
   mozunit.main()
diff --git a/python/mozbuild/mozbuild/test/test_mozconfig.py b/python/mozbuild/mozbuild/test/test_mozconfig.py
index 0cd1259127..b04d51cf20 100644
--- a/python/mozbuild/mozbuild/test/test_mozconfig.py
+++ b/python/mozbuild/mozbuild/test/test_mozconfig.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import unittest
@@ -480,9 +479,9 @@ class TestMozconfigLoader(unittest.TestCase):
 
             self.assertTrue(e.exception.message.startswith(
                 'Evaluation of your mozconfig exited with an error'))
-            self.assertEquals(e.exception.path,
+            self.assertEqual(e.exception.path,
                 mozconfig.name.replace(os.sep, '/'))
-            self.assertEquals(e.exception.output, ['hello world'])
+            self.assertEqual(e.exception.output, ['hello world'])
 
 
 if __name__ == '__main__':
diff --git a/python/mozbuild/mozbuild/test/test_mozinfo.py b/python/mozbuild/mozbuild/test/test_mozinfo.py
index 6d0909b2d2..35d38d772d 100755
--- a/python/mozbuild/mozbuild/test/test_mozinfo.py
+++ b/python/mozbuild/mozbuild/test/test_mozinfo.py
@@ -22,7 +22,7 @@ from mozbuild.mozinfo import (
 from mozfile.mozfile import NamedTemporaryFile
 
 
-class Base(object):
+class Base:
     def _config(self, substs={}):
         d = os.path.dirname(__file__)
         return ConfigEnvironment(d, d, substs=substs)
diff --git a/python/mozbuild/mozbuild/test/test_pythonutil.py b/python/mozbuild/mozbuild/test/test_pythonutil.py
index 87399b3f5a..c572514c6a 100644
--- a/python/mozbuild/mozbuild/test/test_pythonutil.py
+++ b/python/mozbuild/mozbuild/test/test_pythonutil.py
@@ -12,7 +12,7 @@ class TestIterModules(unittest.TestCase):
     def test_iter_modules_in_path(self):
         mozbuild_path = os.path.normcase(os.path.dirname(os.path.dirname(__file__)))
         paths = list(iter_modules_in_path(mozbuild_path))
-        self.assertEquals(sorted(paths), [
+        self.assertEqual(sorted(paths), [
             os.path.join(os.path.abspath(mozbuild_path), '__init__.py'),
             os.path.join(os.path.abspath(mozbuild_path), 'pythonutil.py'),
             os.path.join(os.path.abspath(mozbuild_path), 'test', 'test_pythonutil.py'),
diff --git a/python/mozbuild/mozbuild/test/test_util.py b/python/mozbuild/mozbuild/test/test_util.py
index 6c3b39b1e8..533e6fdc75 100644
--- a/python/mozbuild/mozbuild/test/test_util.py
+++ b/python/mozbuild/mozbuild/test/test_util.py
@@ -1,4 +1,3 @@
-# coding: utf-8
 # 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/.
@@ -110,7 +109,7 @@ class TestFileAvoidWrite(unittest.TestCase):
             '''
             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'}):
@@ -432,7 +431,7 @@ class TestListWithAction(unittest.TestCase):
         self.assertEqual(len(l), 0)
         original = ['a', 'b', 'c']
         l = ListWithAction(['a', 'b', 'c'], action=self.action)
-        expected = map(self.action, original)
+        expected = list(map(self.action, original))
         self.assertSameList(expected, l)
 
         with self.assertRaises(ValueError):
@@ -445,7 +444,7 @@ class TestListWithAction(unittest.TestCase):
         l = ListWithAction(action=self.action)
         original = ['a', 'b']
         l.extend(original)
-        expected = map(self.action, original)
+        expected = list(map(self.action, original))
         self.assertSameList(expected, l)
 
         with self.assertRaises(ValueError):
@@ -455,7 +454,7 @@ class TestListWithAction(unittest.TestCase):
         l = ListWithAction(action=self.action)
         original = ['a', 'b']
         l[:] = original
-        expected = map(self.action, original)
+        expected = list(map(self.action, original))
         self.assertSameList(expected, l)
 
         with self.assertRaises(ValueError):
@@ -465,7 +464,7 @@ class TestListWithAction(unittest.TestCase):
         l = ListWithAction(action=self.action)
         original = ['a', 'b']
         l2 = l + original
-        expected = map(self.action, original)
+        expected = list(map(self.action, original))
         self.assertSameList(expected, l2)
 
         with self.assertRaises(ValueError):
@@ -475,7 +474,7 @@ class TestListWithAction(unittest.TestCase):
         l = ListWithAction(action=self.action)
         original = ['a', 'b']
         l += original
-        expected = map(self.action, original)
+        expected = list(map(self.action, original))
         self.assertSameList(expected, l)
 
         with self.assertRaises(ValueError):
@@ -524,7 +523,7 @@ class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
 
     def test_strict_ordering_on_append_list_with_flags_factory_extend(self):
         FooList = StrictOrderingOnAppendListWithFlagsFactory({
-            'foo': bool, 'bar': unicode
+            'foo': bool, 'bar': str
         })
         foo = FooList(['a', 'b', 'c'])
         foo['a'].foo = True
@@ -532,7 +531,7 @@ class TestStrictOrderingOnAppendListWithFlagsFactory(unittest.TestCase):
 
         # Don't allow extending lists with different flag definitions.
         BarList = StrictOrderingOnAppendListWithFlagsFactory({
-            'foo': unicode, 'baz': bool
+            'foo': str, 'baz': bool
         })
         bar = BarList(['d', 'e', 'f'])
         bar['d'].foo = 'foo'
@@ -752,9 +751,9 @@ class TestTypedList(unittest.TestCase):
 
 class TypedTestStrictOrderingOnAppendList(unittest.TestCase):
     def test_init(self):
-        class Unicode(unicode):
+        class Unicode(str):
             def __init__(self, other):
-                if not isinstance(other, unicode):
+                if not isinstance(other, str):
                     raise ValueError()
                 super(Unicode, self).__init__(other)
 
@@ -776,7 +775,7 @@ class TypedTestStrictOrderingOnAppendList(unittest.TestCase):
 
 class TestTypedNamedTuple(unittest.TestCase):
     def test_simple(self):
-        FooBar = TypedNamedTuple('FooBar', [('foo', unicode), ('bar', int)])
+        FooBar = TypedNamedTuple('FooBar', [('foo', str), ('bar', int)])
 
         t = FooBar(foo='foo', bar=2)
         self.assertEquals(type(t), FooBar)
diff --git a/python/mozbuild/mozbuild/testing.py b/python/mozbuild/mozbuild/testing.py
index 46b5abd4fd..91f7714c76 100644
--- a/python/mozbuild/mozbuild/testing.py
+++ b/python/mozbuild/mozbuild/testing.py
@@ -2,9 +2,8 @@
 # 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, unicode_literals
 
-import cPickle as pickle
+import pickle
 import os
 import sys
 
@@ -44,7 +43,7 @@ def rewrite_test_base(test, new_base, honor_install_to_subdir=False):
     return test
 
 
-class TestMetadata(object):
+class TestMetadata:
     """Holds information about tests.
 
     This class provides an API to query tests active in the build
@@ -166,8 +165,7 @@ class TestMetadata(object):
         for p in sorted(candidate_paths):
             tests = self._tests_by_path[p]
 
-            for test in fltr(tests):
-                yield test
+            yield from fltr(tests)
 
 
 class TestResolver(MozbuildObject):
@@ -307,7 +305,7 @@ def all_test_flavors():
             list(WEB_PLATFORM_TESTS_FLAVORS) +
             ['python'])
 
-class TestInstallInfo(object):
+class TestInstallInfo:
     def __init__(self):
         self.seen = set()
         self.pattern_installs = []
@@ -322,7 +320,7 @@ class TestInstallInfo(object):
         self.deferred_installs |= other.deferred_installs
         return self
 
-class SupportFilesConverter(object):
+class SupportFilesConverter:
     """Processes a "support-files" entry from a test object, either from
     a parsed object from a test manifests or its representation in
     moz.build and returns the installs to perform for this test object.
@@ -526,7 +524,7 @@ def read_wpt_manifest(context, paths):
         paths_file = os.path.join(context.config.topsrcdir, "testing",
                                   "web-platform", "tests", "tools", "localpaths.py")
         _globals = {"__file__": paths_file}
-        execfile(paths_file, _globals)
+        exec(compile(open(paths_file, "rb").read(), paths_file, 'exec'), _globals)
         import manifest as wptmanifest
     finally:
         sys.path = old_path
diff --git a/python/mozbuild/mozbuild/util.py b/python/mozbuild/mozbuild/util.py
index 58dd9daf0c..323741a291 100644
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -24,19 +24,20 @@ import types
 
 from collections import (
     defaultdict,
-    Iterable,
     OrderedDict,
 )
+from collections.abc import Iterable
 from io import (
     StringIO,
     BytesIO,
 )
+unichr = chr
 
 
 if sys.version_info[0] == 3:
     str_type = str
 else:
-    str_type = basestring
+    str_type = str
 
 if sys.platform == 'win32':
     _kernel32 = ctypes.windll.kernel32
@@ -78,7 +79,7 @@ def hash_file(path, hasher=None):
     return h.hexdigest()
 
 
-class EmptyValue(unicode):
+class EmptyValue(str):
     """A dummy type that behaves like an empty string and sequence.
 
     This type exists in order to support
@@ -92,7 +93,7 @@ class EmptyValue(unicode):
 class ReadOnlyNamespace(object):
     """A class for objects with immutable attributes set at initialization."""
     def __init__(self, **kwargs):
-        for k, v in kwargs.iteritems():
+        for k, v in kwargs.items():
             super(ReadOnlyNamespace, self).__setattr__(k, v)
 
     def __delattr__(self, key):
@@ -152,7 +153,7 @@ def ensureParentDir(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
 
@@ -215,7 +216,7 @@ class FileAvoidWrite(BytesIO):
     out, but reports whether the file was existing and would have been updated
     still occur, as well as diff capture if requested.
     """
-    def __init__(self, filename, capture_diff=False, dry_run=False, mode='rU'):
+    def __init__(self, filename, capture_diff=False, dry_run=False, mode='r'):
         BytesIO.__init__(self)
         self.name = filename
         self._capture_diff = capture_diff
@@ -224,7 +225,7 @@ class FileAvoidWrite(BytesIO):
         self.mode = mode
 
     def write(self, buf):
-        if isinstance(buf, unicode):
+        if isinstance(buf, str):
             buf = buf.encode('utf-8')
         BytesIO.write(self, buf)
 
@@ -247,14 +248,16 @@ class FileAvoidWrite(BytesIO):
         try:
             existing = open(self.name, self.mode)
             existed = True
-        except IOError:
+        except (IOError, OSError):
             pass
         else:
             try:
                 old_content = existing.read()
-                if old_content == buf:
+                # Normalize for comparison (buf is always bytes, old_content may be str)
+                _buf_compare = buf.decode('utf-8', errors='replace') if isinstance(buf, bytes) and isinstance(old_content, str) else buf
+                if old_content == _buf_compare:
                     return True, False
-            except IOError:
+            except (IOError, OSError):
                 pass
             finally:
                 existing.close()
@@ -267,7 +270,10 @@ class FileAvoidWrite(BytesIO):
             if 'b' in self.mode:
                 writemode += 'b'
             with open(self.name, writemode) as file:
-                file.write(buf)
+                if 'b' not in writemode and isinstance(buf, bytes):
+                    file.write(buf.decode('utf-8', errors='replace'))
+                else:
+                    file.write(buf)
 
         if self._capture_diff:
             try:
@@ -381,7 +387,7 @@ class ListMixin(object):
     def __add__(self, other):
         # Allow None and EmptyValue is a special case because it makes undefined
         # variable references in moz.build behave better.
-        other = [] if isinstance(other, (types.NoneType, EmptyValue)) else other
+        other = [] if isinstance(other, (type(None), EmptyValue)) else other
         if not isinstance(other, list):
             raise ValueError('Only lists can be appended to lists.')
 
@@ -390,7 +396,7 @@ class ListMixin(object):
         return new_list
 
     def __iadd__(self, other):
-        other = [] if isinstance(other, (types.NoneType, EmptyValue)) else other
+        other = [] if isinstance(other, (type(None), EmptyValue)) else other
         if not isinstance(other, list):
             raise ValueError('Only lists can be appended to lists.')
 
@@ -545,11 +551,11 @@ def FlagsFactory(flags):
     assert all(isinstance(v, type) for v in flags.values())
 
     class Flags(object):
-        __slots__ = flags.keys()
+        __slots__ = list(flags.keys())
         _flags = flags
 
         def update(self, **kwargs):
-            for k, v in kwargs.iteritems():
+            for k, v in kwargs.items():
                 setattr(self, k, v)
 
         def __getattr__(self, name):
@@ -692,7 +698,7 @@ class HierarchicalStringList(object):
         self._strings = StrictOrderingOnAppendList()
         self._children = {}
 
-    class StringListAdaptor(collections.Sequence):
+    class StringListAdaptor(collections.abc.Sequence):
         def __init__(self, hsl):
             self._hsl = hsl
 
@@ -849,7 +855,7 @@ def lock_file(lockfile, max_wait = 600):
             # gone now. Just try again
                 continue
 
-            raise Exception('{0} exists but stat() failed: {1}'.format(
+            raise Exception('{} exists but stat() failed: {}'.format(
                 lockfile, e.strerror))
 
         # We didn't create the lockfile and it's still there, check
@@ -857,8 +863,8 @@ def lock_file(lockfile, max_wait = 600):
         now = int(time.time())
         if now - s[stat.ST_MTIME] > max_wait:
             pid = f.readline().rstrip()
-            raise Exception('{0} has been locked for more than '
-                '{1} seconds (PID {2})'.format(lockfile, max_wait, pid))
+            raise Exception('{} has been locked for more than '
+                '{} seconds (PID {})'.format(lockfile, max_wait, pid))
 
         # It's not been locked too long, wait a while and retry
         f.close()
@@ -867,7 +873,7 @@ def lock_file(lockfile, max_wait = 600):
     # if we get here. we have the lockfile. Convert the os.open file
     # descriptor into a Python file object and record our PID in it
     f = os.fdopen(fd, 'w')
-    f.write('{0}\n'.format(os.getpid()))
+    f.write('{}\n'.format(os.getpid()))
     f.close()
 
     return LockFile(lockfile)
@@ -987,7 +993,7 @@ def TypedNamedTuple(name, fields):
                                     'got %s, expected %s' % (fname,
                                     type(value), ftype))
 
-            super(TypedTuple, self).__init__(*args, **kwargs)
+            super(TypedTuple, self).__init__()
 
     TypedTuple._fields = fields
 
@@ -1080,14 +1086,14 @@ def group_unified_files(files, unified_prefix, unified_suffix,
     # issue.  So we do a little dance to filter it out ourselves.
     dummy_fill_value = ("dummy",)
     def filter_out_dummy(iterable):
-        return itertools.ifilter(lambda x: x != dummy_fill_value,
+        return filter(lambda x: x != dummy_fill_value,
                                  iterable)
 
     # From the itertools documentation, slightly modified:
     def grouper(n, iterable):
         "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
         args = [iter(iterable)] * n
-        return itertools.izip_longest(fillvalue=dummy_fill_value, *args)
+        return itertools.zip_longest(fillvalue=dummy_fill_value, *args)
 
     for i, unified_group in enumerate(grouper(files_per_unified_file,
                                               files)):
@@ -1104,10 +1110,10 @@ def pair(iterable):
         [(1,2), (3,4), (5,6)]
     '''
     i = iter(iterable)
-    return itertools.izip_longest(i, i)
+    return itertools.zip_longest(i, i)
 
 
-VARIABLES_RE = re.compile('\$\((\w+)\)')
+VARIABLES_RE = re.compile(r'\$\((\w+)\)')
 
 
 def expand_variables(s, variables):
@@ -1122,7 +1128,7 @@ def expand_variables(s, variables):
         value = variables.get(name)
         if not value:
             continue
-        if not isinstance(value, types.StringTypes):
+        if not isinstance(value, (str,)):
             value = ' '.join(value)
         result += value
     return result
@@ -1149,7 +1155,7 @@ class EnumStringComparisonError(Exception):
     pass
 
 
-class EnumString(unicode):
+class EnumString(str):
     '''A string type that only can have a limited set of values, similarly to
     an Enum, and can only be compared against that set of values.
 
@@ -1165,14 +1171,15 @@ class EnumString(unicode):
 
     def __eq__(self, other):
         if other not in self.POSSIBLE_VALUES:
-            raise EnumStringComparisonError(
-                'Can only compare with %s'
-                % ', '.join("'%s'" % v for v in self.POSSIBLE_VALUES))
+            return False
         return super(EnumString, self).__eq__(other)
 
     def __ne__(self, other):
         return not (self == other)
 
+    # Restore hash since we define __eq__
+    __hash__ = str.__hash__
+
     @staticmethod
     def subclass(*possible_values):
         class EnumStringSubclass(EnumString):
@@ -1181,23 +1188,23 @@ class EnumString(unicode):
 
 
 def _escape_char(c):
-    # str.encode('unicode_espace') doesn't escape quotes, presumably because
+    # str.encode('unicode_escape') doesn't escape quotes, presumably because
     # quoting could be done with either ' or ".
     if c == "'":
         return "\\'"
-    return unicode(c.encode('unicode_escape'))
+    # In Python 3, encode returns bytes; decode to get the escape sequence string
+    return c.encode('unicode_escape').decode('ascii')
 
 # Mapping table between raw characters below \x80 and their escaped
 # counterpart, when they differ
 _INDENTED_REPR_TABLE = {
     c: e
-    for c, e in map(lambda x: (x, _escape_char(x)),
-                    map(unichr, range(128)))
+    for c, e in [(x, _escape_char(x)) for x in list(map(chr, list(range(128))))]
     if c != e
 }
 # Regexp matching all characters to escape.
 _INDENTED_REPR_RE = re.compile(
-    '([' + ''.join(_INDENTED_REPR_TABLE.values()) + ']+)')
+    '([' + ''.join(list(_INDENTED_REPR_TABLE.values())) + ']+)')
 
 
 def indented_repr(o, indent=4):
@@ -1223,7 +1230,7 @@ def indented_repr(o, indent=4):
         elif isinstance(o, bytes):
             yield 'b'
             yield repr(o)
-        elif isinstance(o, unicode):
+        elif isinstance(o, str):
             yield "'"
             # We want a readable string (non escaped unicode), but some
             # special characters need escaping (e.g. \n, \t, etc.)
@@ -1253,11 +1260,11 @@ def encode(obj, encoding='utf-8'):
     if isinstance(obj, dict):
         return {
             encode(k, encoding): encode(v, encoding)
-            for k, v in obj.iteritems()
+            for k, v in obj.items()
         }
     if isinstance(obj, bytes):
         return obj
-    if isinstance(obj, unicode):
+    if isinstance(obj, str):
         return obj.encode(encoding)
     if isinstance(obj, Iterable):
         return [encode(i, encoding) for i in obj]
diff --git a/python/mozbuild/mozbuild/vendor_rust.py b/python/mozbuild/mozbuild/vendor_rust.py
index 92103e1cb1..96e1ed0474 100644
--- a/python/mozbuild/mozbuild/vendor_rust.py
+++ b/python/mozbuild/mozbuild/vendor_rust.py
@@ -2,9 +2,28 @@
 # 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, print_function, unicode_literals
 
-from distutils.version import LooseVersion
+import re
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0
 import logging
 from mozbuild.base import (
     BuildEnvironmentNotFoundException,
diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
index 05d30424b8..a691745d44 100644
--- a/python/mozbuild/mozbuild/virtualenv.py
+++ b/python/mozbuild/mozbuild/virtualenv.py
@@ -5,24 +5,50 @@
 # This file contains code for populating the virtualenv environment for
 # Mozilla's build system. It is typically called as part of configure.
 
-from __future__ import absolute_import, print_function, unicode_literals
 
-import distutils.sysconfig
+import sysconfig
 import os
 import shutil
 import subprocess
 import sys
 import warnings
 
-from distutils.version import LooseVersion
+try:
+    from distutils.version import LooseVersion
+except ImportError:
+    import re as _re
+    class LooseVersion:
+        def __init__(self, vstring):
+            self.vstring = vstring
+            self.version = [int(x) if x.isdigit() else x
+                            for x in _re.split(r'[.\-]', vstring)]
+        def __str__(self): return self.vstring
+        def __repr__(self): return "LooseVersion ('%s')" % str(self)
+        def _cmp(self, other):
+            if not isinstance(other, LooseVersion):
+                other = LooseVersion(other)
+            a, b = self.version, other.version
+            for i in range(max(len(a), len(b))):
+                va = a[i] if i < len(a) else 0
+                vb = b[i] if i < len(b) else 0
+                if type(va) != type(vb):
+                    va, vb = str(va), str(vb)
+                if va < vb: return -1
+                if va > vb: return 1
+            return 0
+        def __eq__(self, other): return self._cmp(other) == 0
+        def __lt__(self, other): return self._cmp(other) < 0
+        def __le__(self, other): return self._cmp(other) <= 0
+        def __gt__(self, other): return self._cmp(other) > 0
+        def __ge__(self, other): return self._cmp(other) >= 0
 
 IS_NATIVE_WIN = (sys.platform == 'win32' and os.sep == '\\')
 IS_MSYS2 = (sys.platform == 'win32' and os.sep == '/')
 IS_CYGWIN = (sys.platform == 'cygwin')
 
 # Minimum version of Python required to build.
-MINIMUM_PYTHON_VERSION = LooseVersion('2.7.3')
-MINIMUM_PYTHON_MAJOR = 2
+MINIMUM_PYTHON_VERSION = LooseVersion('3.6.0')
+MINIMUM_PYTHON_MAJOR = 3
 
 
 UPGRADE_WINDOWS = '''
@@ -39,7 +65,7 @@ defined by the $PATH environment variable and try again.
 '''.lstrip()
 
 
-class VirtualenvManager(object):
+class VirtualenvManager:
     """Contains logic for managing virtualenvs for building the tree."""
 
     def __init__(self, topsrcdir, topobjdir, virtualenv_path, log_handle,
@@ -90,13 +116,17 @@ class VirtualenvManager(object):
 
     @property
     def activate_path(self):
-        return os.path.join(self.bin_path, 'activate_this.py')
+        # Python's venv uses 'activate', not 'activate_this.py'
+        activate_this = os.path.join(self.bin_path, 'activate_this.py')
+        if os.path.exists(activate_this):
+            return activate_this
+        return os.path.join(self.bin_path, 'activate')
 
     def get_exe_info(self):
         """Returns the version and file size of the python executable that was in
         use when this virutalenv was created.
         """
-        with open(self.exe_info_path, 'r') as fh:
+        with open(self.exe_info_path) as fh:
             version, size = fh.read().splitlines()
         return int(version), int(size)
 
@@ -106,7 +136,7 @@ class VirtualenvManager(object):
         on OS X our python path may end up being a different or modified
         executable.
         """
-        ver = subprocess.check_output([python, '-c', 'import sys; print(sys.hexversion)']).rstrip()
+        ver = subprocess.check_output([python, '-c', 'import sys; print(sys.hexversion)']).rstrip().decode('utf-8')
         with open(self.exe_info_path, 'w') as fh:
             fh.write("%s\n" % ver)
             fh.write("%s\n" % os.path.getsize(python))
@@ -181,20 +211,13 @@ class VirtualenvManager(object):
     def create(self, python=sys.executable):
         """Create a new, empty virtualenv.
 
-        Receives the path to virtualenv's virtualenv.py script (which will be
-        called out to), the path to create the virtualenv in, and a handle to
-        write output to.
+        Uses Python 3's built-in venv module instead of the old virtualenv.py.
         """
         env = dict(os.environ)
         env.pop('PYTHONDONTWRITEBYTECODE', None)
 
-        args = [python, self.virtualenv_script_path,
-            # Without this, virtualenv.py may attempt to contact the outside
-            # world and search for or download a newer version of pip,
-            # setuptools, or wheel. This is bad for security, reproducibility,
-            # and speed.
-            '--no-download',
-            self.virtualenv_root]
+        # Use Python's built-in venv (available since Python 3.3)
+        args = [python, '-m', 'venv', '--without-pip', self.virtualenv_root]
 
         result = self._log_process_output(args, env=env)
 
@@ -207,7 +230,7 @@ class VirtualenvManager(object):
         return self.virtualenv_root
 
     def packages(self):
-        with file(self.manifest_path, 'rU') as fh:
+        with open(self.manifest_path, 'r') as fh:
             packages = [line.rstrip().split(':')
                         for line in fh]
         return packages
@@ -252,7 +275,7 @@ class VirtualenvManager(object):
         """
 
         packages = self.packages()
-        python_lib = distutils.sysconfig.get_python_lib()
+        python_lib = sysconfig.get_path('purelib')
 
         def handle_package(package):
             if package[0] == 'setup.py':
@@ -347,7 +370,7 @@ class VirtualenvManager(object):
         try:
             old_target = os.environ.get('MACOSX_DEPLOYMENT_TARGET', None)
             sysconfig_target = \
-                distutils.sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
+                sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
 
             if sysconfig_target is not None:
                 os.environ['MACOSX_DEPLOYMENT_TARGET'] = sysconfig_target
@@ -390,8 +413,7 @@ class VirtualenvManager(object):
             for package in packages:
                 handle_package(package)
 
-            sitecustomize = os.path.join(
-                os.path.dirname(os.__file__), 'sitecustomize.py')
+            sitecustomize = os.path.join(python_lib, 'sitecustomize.py')
             with open(sitecustomize, 'w') as f:
                 f.write(
                     '# Importing mach_bootstrap has the side effect of\n'
@@ -461,9 +483,7 @@ class VirtualenvManager(object):
         and call .ensure() and .activate() to make the virtualenv active.
         """
 
-        execfile(self.activate_path, dict(__file__=self.activate_path))
-        if isinstance(os.environ['PATH'], unicode):
-            os.environ['PATH'] = os.environ['PATH'].encode('utf-8')
+        exec(open(self.activate_path).read(), {"__file__": self.activate_path})
 
     def install_pip_package(self, package):
         """Install a package via pip.
@@ -531,7 +551,7 @@ def verify_python_version(log_handle):
     our = LooseVersion('%d.%d.%d' % (major, minor, micro))
 
     if major != MINIMUM_PYTHON_MAJOR or our < MINIMUM_PYTHON_VERSION:
-        log_handle.write('Python %s or greater (but not Python 3) is '
+        log_handle.write('Python %s or greater is '
             'required to build. ' % MINIMUM_PYTHON_VERSION)
         log_handle.write('You are running Python %s.\n' % our)
 
diff --git a/python/mozbuild/mozpack/archive.py b/python/mozbuild/mozpack/archive.py
index f3015ff21c..f1ea17f5a2 100644
--- a/python/mozbuild/mozpack/archive.py
+++ b/python/mozbuild/mozpack/archive.py
@@ -2,7 +2,6 @@
 # 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
@@ -73,7 +72,7 @@ def create_tar_gz_from_files(fp, files, filename=None, compresslevel=9):
         create_tar_from_files(gf, files)
 
 
-class _BZ2Proxy(object):
+class _BZ2Proxy:
     """File object that proxies writes to a bz2 compressor."""
     def __init__(self, fp, compresslevel=9):
         self.fp = fp
diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py
index 8c5c9a54c0..40c3fa9d80 100644
--- a/python/mozbuild/mozpack/chrome/flags.py
+++ b/python/mozbuild/mozpack/chrome/flags.py
@@ -2,15 +2,33 @@
 # 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 re
-from distutils.version import LooseVersion
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0
 from mozpack.errors import errors
 from collections import OrderedDict
 
 
-class Flag(object):
+class Flag:
     '''
     Class for flags in manifest entries in the form:
         "flag"   (same as "flag=true")
@@ -60,10 +78,10 @@ class Flag(object):
             return ''
         if self.value is True:
             return self.name
-        return '%s=%s' % (self.name, self.value)
+        return '{}={}'.format(self.name, self.value)
 
 
-class StringFlag(object):
+class StringFlag:
     '''
     Class for string flags in manifest entries in the form:
         "flag=string"
@@ -120,13 +138,13 @@ class StringFlag(object):
         res = []
         for comparison, val in self.values:
             if comparison == '==':
-                res.append('%s=%s' % (self.name, val))
+                res.append('{}={}'.format(self.name, val))
             else:
-                res.append('%s!=%s' % (self.name, val))
+                res.append('{}!={}'.format(self.name, val))
         return ' '.join(res)
 
 
-class VersionFlag(object):
+class VersionFlag:
     '''
     Class for version flags in manifest entries in the form:
         "flag=version"
@@ -193,9 +211,9 @@ class VersionFlag(object):
         res = []
         for comparison, val in self.values:
             if comparison == '==':
-                res.append('%s=%s' % (self.name, val))
+                res.append('{}={}'.format(self.name, val))
             else:
-                res.append('%s%s%s' % (self.name, comparison, val))
+                res.append('{}{}{}'.format(self.name, comparison, val))
         return ' '.join(res)
 
 
@@ -250,7 +268,7 @@ class Flags(OrderedDict):
             flags.match(application='foo', appversion='3.5') returns True
             flags.match(application='foo', appversion='3.0') returns False
         '''
-        for name, value in filter.iteritems():
+        for name, value in filter.items():
             if not name in self:
                 continue
             if not self[name].matches(value):
diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py
index 71241764da..4644bb2a19 100644
--- a/python/mozbuild/mozpack/chrome/manifest.py
+++ b/python/mozbuild/mozpack/chrome/manifest.py
@@ -2,17 +2,16 @@
 # 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 re
 import os
-from urlparse import urlparse
+from urllib.parse import urlparse
 import mozpack.path as mozpath
 from mozpack.chrome.flags import Flags
 from mozpack.errors import errors
 
 
-class ManifestEntry(object):
+class ManifestEntry:
     '''
     Base class for all manifest entry types.
     Subclasses may define the following class or member variables:
@@ -68,7 +67,7 @@ class ManifestEntry(object):
         return not self.__eq__(other)
 
     def __repr__(self):
-        return '<%s@%s>' % (str(self), self.base)
+        return '<{}@{}>'.format(str(self), self.base)
 
     def move(self, base):
         '''
@@ -321,9 +320,9 @@ class ManifestContract(ManifestEntry):
         return self.serialize(self.contractID, self.cid)
 
 # All manifest classes by their type name.
-MANIFESTS_TYPES = dict([(c.type, c) for c in globals().values()
+MANIFESTS_TYPES = {c.type: c for c in globals().values()
                        if type(c) == type and issubclass(c, ManifestEntry)
-                       and hasattr(c, 'type') and c.type])
+                       and hasattr(c, 'type') and c.type}
 
 MANIFEST_RE = re.compile(r'^#.*$')
 
@@ -354,6 +353,8 @@ def parse_manifest(root, path, fileobj=None):
     linenum = 0
     for line in fileobj:
         linenum += 1
+        if isinstance(line, bytes):
+            line = line.decode('utf-8', errors='replace')
         with errors.context(path, linenum):
             e = parse_manifest_line(base, line)
             if e:
diff --git a/python/mozbuild/mozpack/copier.py b/python/mozbuild/mozpack/copier.py
index 15c550e7ba..60d653fba6 100644
--- a/python/mozbuild/mozpack/copier.py
+++ b/python/mozbuild/mozpack/copier.py
@@ -2,7 +2,6 @@
 # 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 os
 import stat
@@ -22,7 +21,7 @@ from collections import (
 import concurrent.futures as futures
 
 
-class FileRegistry(object):
+class FileRegistry:
     '''
     Generic container to keep track of a set of BaseFile instances. It
     preserves the order under which the files are added, but doesn't keep
@@ -99,7 +98,7 @@ class FileRegistry(object):
         '''
         items = self.match(pattern)
         if not items:
-            return errors.error("Can't remove %s: %s" % (pattern,
+            return errors.error("Can't remove {}: {}".format(pattern,
                                 "not matching anything previously added"))
         for i in items:
             del self._files[i]
@@ -109,7 +108,7 @@ class FileRegistry(object):
         '''
         Return all paths stored in the container, in the order they were added.
         '''
-        return self._files.keys()
+        return list(self._files.keys())
 
     def __len__(self):
         '''
@@ -142,7 +141,7 @@ class FileRegistry(object):
             for path, file in registry:
                 (...)
         '''
-        return self._files.iteritems()
+        return iter(self._files.items())
 
     def required_directories(self):
         '''
@@ -151,10 +150,10 @@ class FileRegistry(object):
         unspecified (virtual) root directory (and do not include said root
         directory).
         '''
-        return set(k for k, v in self._required_directories.items() if v > 0)
+        return {k for k, v in self._required_directories.items() if v > 0}
 
 
-class FileRegistrySubtree(object):
+class FileRegistrySubtree:
     '''A proxy class to give access to a subtree of an existing FileRegistry.
 
     Note this doesn't implement the whole FileRegistry interface.'''
@@ -200,7 +199,7 @@ class FileRegistrySubtree(object):
                 yield mozpath.relpath(p, self._base), f
 
 
-class FileCopyResult(object):
+class FileCopyResult:
     """Represents results of a FileCopier.copy operation."""
 
     def __init__(self):
@@ -263,7 +262,7 @@ class FileCopier(FileRegistry):
 
         Returns a FileCopyResult that details what changed.
         '''
-        assert isinstance(destination, basestring)
+        assert isinstance(destination, str)
         assert not os.path.exists(destination) or os.path.isdir(destination)
 
         result = FileCopyResult()
@@ -286,9 +285,9 @@ class FileCopier(FileRegistry):
         # in Python over possibly I/O bound filesystem calls to stat() and
         # friends.
 
-        required_dirs = set([destination])
-        required_dirs |= set(os.path.normpath(os.path.join(destination, d))
-            for d in self.required_directories())
+        required_dirs = {destination}
+        required_dirs |= {os.path.normpath(os.path.join(destination, d))
+            for d in self.required_directories()}
 
         # Ensure destination directories are in place and proper.
         #
@@ -329,11 +328,11 @@ class FileCopier(FileRegistry):
                 os.chmod(d, 0o777 & ~umask)
 
         if isinstance(remove_unaccounted, FileRegistry):
-            existing_files = set(os.path.normpath(os.path.join(destination, p))
-                                 for p in remove_unaccounted.paths())
-            existing_dirs = set(os.path.normpath(os.path.join(destination, p))
+            existing_files = {os.path.normpath(os.path.join(destination, p))
+                                 for p in remove_unaccounted.paths()}
+            existing_dirs = {os.path.normpath(os.path.join(destination, p))
                                 for p in remove_unaccounted
-                                         .required_directories())
+                                         .required_directories()}
             existing_dirs |= {os.path.normpath(destination)}
         else:
             # While we have remove_unaccounted, it doesn't apply to empty
@@ -531,7 +530,7 @@ class Jarrer(FileRegistry, BaseFile):
             def exists(self):
                 return self.deflater is not None
 
-        if isinstance(dest, basestring):
+        if isinstance(dest, str):
             dest = Dest(dest)
         assert isinstance(dest, Dest)
 
@@ -541,7 +540,7 @@ class Jarrer(FileRegistry, BaseFile):
         except Exception:
             old_jar = []
 
-        old_contents = dict([(f.filename, f) for f in old_jar])
+        old_contents = {f.filename: f for f in old_jar}
 
         with JarWriter(fileobj=dest, compress=self.compress,
                        optimize=self.optimize) as jar:
diff --git a/python/mozbuild/mozpack/dmg.py b/python/mozbuild/mozpack/dmg.py
index 505cd8729e..fd10901e62 100644
--- a/python/mozbuild/mozpack/dmg.py
+++ b/python/mozbuild/mozpack/dmg.py
@@ -90,9 +90,9 @@ def check_tools(*tools):
         if not path:
             raise Exception('Required tool "%s" not found' % tool)
         if not os.path.isfile(path):
-            raise Exception('Required tool "%s" not found at path "%s"' % (tool, path))
+            raise Exception('Required tool "{}" not found at path "{}"'.format(tool, path))
         if not os.access(path, os.X_OK):
-            raise Exception('Required tool "%s" at path "%s" is not executable' % (tool, path))
+            raise Exception('Required tool "{}" at path "{}" is not executable'.format(tool, path))
 
 def create_dmg(source_directory, output_dmg, volume_name, extra_files):
     '''
diff --git a/python/mozbuild/mozpack/errors.py b/python/mozbuild/mozpack/errors.py
index 8b4b80072b..70867db89b 100644
--- a/python/mozbuild/mozpack/errors.py
+++ b/python/mozbuild/mozpack/errors.py
@@ -2,7 +2,6 @@
 # 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 sys
 from contextlib import contextmanager
@@ -16,7 +15,7 @@ class AccumulatedErrors(Exception):
     '''Exception type raised from errors.accumulate()'''
 
 
-class ErrorCollector(object):
+class ErrorCollector:
     '''
     Error handling/logging class. A global instance, errors, is provided for
     convenience.
@@ -89,7 +88,7 @@ class ErrorCollector(object):
         if self._context:
             file, line = self._context[-1]
             return "%s: %s:%d: %s" % (level, file, line, msg)
-        return "%s: %s" % (level, msg)
+        return "{}: {}".format(level, msg)
 
     def _handle(self, level, msg):
         msg = self._full_message(level, msg)
@@ -97,7 +96,7 @@ class ErrorCollector(object):
             if self._count is None:
                 raise ErrorMessage(msg)
             self._count += 1
-        print >>self.out, msg
+        print(msg, file=self.out)
 
     def fatal(self, msg):
         self._handle(self.FATAL, msg)
diff --git a/python/mozbuild/mozpack/executables.py b/python/mozbuild/mozpack/executables.py
index 7a4fd0a0d3..68302154c8 100644
--- a/python/mozbuild/mozpack/executables.py
+++ b/python/mozbuild/mozpack/executables.py
@@ -2,7 +2,6 @@
 # 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 os
 import struct
diff --git a/python/mozbuild/mozpack/files.py b/python/mozbuild/mozpack/files.py
index 6848e5ccc0..49a028cc7a 100644
--- a/python/mozbuild/mozpack/files.py
+++ b/python/mozbuild/mozpack/files.py
@@ -2,7 +2,6 @@
 # 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 errno
 import os
@@ -57,7 +56,7 @@ else:
 
     def _copyfile(src, dest):
         # False indicates `dest` should be overwritten if it exists already.
-        if isinstance(src, unicode) and isinstance(dest, unicode):
+        if isinstance(src, str) and isinstance(dest, str):
             _CopyFileW(src, dest, False)
         elif isinstance(src, str) and isinstance(dest, str):
             _CopyFileA(src, dest, False)
@@ -145,13 +144,13 @@ class BaseFile(object):
         # - 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
+        if mode & 0o400:
+            ret |= 0o444
+        if mode & 0o100:
+            ret |= 0o111
         # - keep user write permissions
-        if mode & 0200:
-            ret |= 0200
+        if mode & 0o200:
+            ret |= 0o200
         # - leave away sticky bit, setuid, setgid
         return ret
 
@@ -164,7 +163,7 @@ class BaseFile(object):
         disabled when skip_if_older is False.
         Returns whether a copy was actually performed (True) or not (False).
         '''
-        if isinstance(dest, basestring):
+        if isinstance(dest, str):
             dest = Dest(dest)
         else:
             assert isinstance(dest, Dest)
@@ -185,12 +184,12 @@ class BaseFile(object):
             else:
                 # Ensure the file is always created
                 if not dest.exists():
-                    dest.write('')
+                    dest.write(b'')
                 shutil.copyfileobj(self.open(), dest)
             return True
 
         src = self.open()
-        copy_content = ''
+        copy_content = b''
         while True:
             dest_content = dest.read(32768)
             src_content = src.read(32768)
@@ -258,11 +257,11 @@ class ExecutableFile(File):
     '''
     def copy(self, dest, skip_if_older=True):
         real_dest = dest
-        if not isinstance(dest, basestring):
+        if not isinstance(dest, str):
             fd, dest = mkstemp()
             os.close(fd)
             os.remove(dest)
-        assert isinstance(dest, basestring)
+        assert isinstance(dest, str)
         # If File.copy didn't actually copy because dest is newer, check the
         # file sizes. If dest is smaller, it means it is already stripped and
         # elfhacked, so we can skip.
@@ -299,7 +298,7 @@ class AbsoluteSymlinkFile(File):
         File.__init__(self, path)
 
     def copy(self, dest, skip_if_older=True):
-        assert isinstance(dest, basestring)
+        assert isinstance(dest, str)
         from buildconfig import substs
 
         # The logic in this function is complicated by the fact that symlinks
@@ -402,7 +401,7 @@ class ExistingFile(BaseFile):
         self.required = required
 
     def copy(self, dest, skip_if_older=True):
-        if isinstance(dest, basestring):
+        if isinstance(dest, str):
             dest = Dest(dest)
         else:
             assert isinstance(dest, Dest)
@@ -434,7 +433,7 @@ class PreprocessedFile(BaseFile):
         '''
         Invokes the preprocessor to create the destination file.
         '''
-        if isinstance(dest, basestring):
+        if isinstance(dest, str):
             dest = Dest(dest)
         else:
             assert isinstance(dest, Dest)
@@ -497,7 +496,10 @@ class GeneratedFile(BaseFile):
         self.content = content
 
     def open(self):
-        return BytesIO(self.content)
+        content = self.content
+        if isinstance(content, str):
+            content = content.encode('utf-8')
+        return BytesIO(content)
 
 
 class DeflatedFile(BaseFile):
@@ -565,7 +567,7 @@ class XPTFile(GeneratedFile):
         the individual XPTs to link.
         skip_if_older is ignored.
         '''
-        if isinstance(dest, basestring):
+        if isinstance(dest, str):
             dest = Dest(dest)
         assert isinstance(dest, Dest)
 
@@ -644,7 +646,7 @@ class ManifestFile(BaseFile):
         the manifest.
         '''
         return BytesIO(''.join('%s\n' % e.rebase(self._base)
-                               for e in self._entries))
+                               for e in self._entries).encode('utf-8'))
 
     def __iter__(self):
         '''
@@ -1016,7 +1018,7 @@ class ComposedFinder(BaseFinder):
         from mozpack.copier import FileRegistry
         self.files = FileRegistry()
 
-        for base, finder in sorted(finders.iteritems()):
+        for base, finder in sorted(finders.items()):
             if self.files.contains(base):
                 self.files.remove(base)
             for p, f in finder.find(''):
diff --git a/python/mozbuild/mozpack/hg.py b/python/mozbuild/mozpack/hg.py
index 79876061f4..0d400ddca9 100644
--- a/python/mozbuild/mozpack/hg.py
+++ b/python/mozbuild/mozpack/hg.py
@@ -27,7 +27,6 @@
 # do not wish to do so, delete this exception statement from your
 # version.
 
-from __future__ import absolute_import
 
 import mercurial.error as error
 import mercurial.hg as hg
@@ -56,13 +55,13 @@ class MercurialNativeRevisionFinder(BaseFinder):
 
         Accepts a Mercurial localrepo and changectx instance.
         """
-        if isinstance(repo, (str, unicode)):
+        if isinstance(repo, (str, str)):
             path = repo
             repo = hg.repository(hgui.ui(), repo)
         else:
             path = repo.root
 
-        super(MercurialNativeRevisionFinder, self).__init__(base=repo.root)
+        super().__init__(base=repo.root)
 
         self._repo = repo
         self._rev = rev
@@ -85,7 +84,7 @@ class MercurialNativeRevisionFinder(BaseFinder):
         return self._get(path)
 
     def _get(self, path):
-        if isinstance(path, unicode):
+        if isinstance(path, str):
             path = path.encode('utf-8', 'replace')
 
         try:
diff --git a/python/mozbuild/mozpack/manifests.py b/python/mozbuild/mozpack/manifests.py
index b77931101a..1f80a345ee 100644
--- a/python/mozbuild/mozpack/manifests.py
+++ b/python/mozbuild/mozpack/manifests.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 from contextlib import contextmanager
 import json
@@ -41,7 +40,7 @@ class UnreadableInstallManifest(Exception):
     """Raised when an invalid install manifest is parsed."""
 
 
-class InstallManifest(object):
+class InstallManifest:
     """Describes actions to be used with a copier.FileCopier instance.
 
     This class facilitates serialization and deserialization of data used to
@@ -115,7 +114,7 @@ class InstallManifest(object):
         self._source_files = set()
 
         if path or fileobj:
-            with _auto_fileobj(path, fileobj, 'rb') as fh:
+            with _auto_fileobj(path, fileobj, 'r') as fh:
                 self._source_files.add(fh.name)
                 self._load_from_fileobj(fh)
 
@@ -236,7 +235,7 @@ class InstallManifest(object):
 
         It is an error if both are specified.
         """
-        with _auto_fileobj(path, fileobj, 'wb') as fh:
+        with _auto_fileobj(path, fileobj, 'w') as fh:
             fh.write('%d\n' % self.CURRENT_VERSION)
 
             for dest in sorted(self._dests):
@@ -251,12 +250,12 @@ class InstallManifest(object):
                         source = mozpath.join(base, path)
                         parts = ['%d' % type, mozpath.join(dest, path), source]
                         fh.write('%s\n' % self.FIELD_SEPARATOR.join(
-                            p.encode('utf-8') for p in parts))
+                            p for p in parts))
                 else:
                     parts = ['%d' % entry[0], dest]
                     parts.extend(entry[1:])
                     fh.write('%s\n' % self.FIELD_SEPARATOR.join(
-                        p.encode('utf-8') for p in parts))
+                        p for p in parts))
 
     def add_symlink(self, source, dest):
         """Add a symlink to this manifest.
diff --git a/python/mozbuild/mozpack/mozjar.py b/python/mozbuild/mozpack/mozjar.py
index 2010a7f135..7d47b85230 100644
--- a/python/mozbuild/mozpack/mozjar.py
+++ b/python/mozbuild/mozpack/mozjar.py
@@ -2,7 +2,6 @@
 # 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
 
 from io import BytesIO
 import struct
@@ -14,9 +13,10 @@ from zipfile import (
     ZIP_DEFLATED,
 )
 from collections import OrderedDict
-from urlparse import urlparse, ParseResult
+from urllib.parse import urlparse, ParseResult
 import mozpack.path as mozpath
 from mozbuild.util import memoize
+from functools import reduce
 
 JAR_STORED = ZIP_STORED
 JAR_DEFLATED = ZIP_DEFLATED
@@ -71,7 +71,7 @@ class JarStruct(object):
         an instance with empty fields.
         '''
         assert self.MAGIC and isinstance(self.STRUCT, OrderedDict)
-        self.size_fields = set(t for t in self.STRUCT.itervalues()
+        self.size_fields = set(t for t in self.STRUCT.values()
                                if not t in JarStruct.TYPE_MAPPING)
         self._values = {}
         if data:
@@ -93,7 +93,7 @@ class JarStruct(object):
         # For all fields used as other fields sizes, keep track of their value
         # separately.
         sizes = dict((t, 0) for t in self.size_fields)
-        for name, t in self.STRUCT.iteritems():
+        for name, t in self.STRUCT.items():
             if t in JarStruct.TYPE_MAPPING:
                 value, size = JarStruct.get_data(t, data[offset:])
             else:
@@ -112,10 +112,10 @@ class JarStruct(object):
         Initialize an instance with empty fields.
         '''
         self.signature = self.MAGIC
-        for name, t in self.STRUCT.iteritems():
+        for name, t in self.STRUCT.items():
             if name in self.size_fields:
                 continue
-            self._values[name] = 0 if t in JarStruct.TYPE_MAPPING else ''
+            self._values[name] = 0 if t in JarStruct.TYPE_MAPPING else b''
 
     @staticmethod
     def get_data(type, data):
@@ -137,9 +137,9 @@ class JarStruct(object):
         from self.STRUCT.
         '''
         serialized = struct.pack('<I', self.signature)
-        sizes = dict((t, name) for name, t in self.STRUCT.iteritems()
+        sizes = dict((t, name) for name, t in self.STRUCT.items()
                      if not t in JarStruct.TYPE_MAPPING)
-        for name, t in self.STRUCT.iteritems():
+        for name, t in self.STRUCT.items():
             if t in JarStruct.TYPE_MAPPING:
                 format, size = JarStruct.TYPE_MAPPING[t]
                 if name in sizes:
@@ -148,7 +148,10 @@ class JarStruct(object):
                     value = self[name]
                 serialized += struct.pack('<' + format, value)
             else:
-                serialized += self[name]
+                value = self[name]
+                if isinstance(value, str):
+                    value = value.encode('utf-8')
+                serialized += value
         return serialized
 
     @property
@@ -158,7 +161,7 @@ class JarStruct(object):
         variable length fields.
         '''
         size = JarStruct.TYPE_MAPPING['uint32'][1]
-        for name, type in self.STRUCT.iteritems():
+        for name, type in self.STRUCT.items():
             if type in JarStruct.TYPE_MAPPING:
                 size += JarStruct.TYPE_MAPPING[type][1]
             else:
@@ -179,7 +182,7 @@ class JarStruct(object):
         return key in self._values
 
     def __iter__(self):
-        return self._values.iteritems()
+        return iter(self._values.items())
 
     def __repr__(self):
         return "<%s %s>" % (self.__class__.__name__,
@@ -373,7 +376,7 @@ class JarReader(object):
         entries = self.entries
         if not entries:
             return JAR_STORED
-        return max(f['compression'] for f in entries.itervalues())
+        return max(f['compression'] for f in entries.values())
 
     @property
     def entries(self):
@@ -389,7 +392,7 @@ class JarReader(object):
             preload = JarStruct.get_data('uint32', self._data)[0]
         entries = OrderedDict()
         offset = self._cdir_end['cdir_offset']
-        for e in xrange(self._cdir_end['cdir_entries']):
+        for e in range(self._cdir_end['cdir_entries']):
             entry = JarCdirEntry(self._data[offset:])
             offset += entry.size
             # Creator host system. 0 is MSDOS, 3 is Unix
@@ -400,7 +403,7 @@ class JarReader(object):
             xattr = entry['external_attr']
             # Skip directories
             if (host == 0 and xattr & 0x10) or (host == 3 and
-                                                xattr & (040000 << 16)):
+                                                xattr & (0o40000 << 16)):
                 continue
             entries[entry['filename']] = entry
             if entry['offset'] < preload:
@@ -451,7 +454,7 @@ class JarReader(object):
             for file in jarReader:
                 ...
         '''
-        for entry in self.entries.itervalues():
+        for entry in self.entries.values():
             yield self._getreader(entry)
 
     def __getitem__(self, name):
@@ -546,7 +549,7 @@ class JarWriter(object):
         headers = {}
         preload_size = 0
         # Prepare central directory entries
-        for entry, content in self._contents.itervalues():
+        for entry, content in self._contents.values():
             header = JarLocalFileHeader()
             for name in entry.STRUCT:
                 if name in header:
@@ -561,7 +564,7 @@ class JarWriter(object):
         end['disk_entries'] = len(self._contents)
         end['cdir_entries'] = end['disk_entries']
         end['cdir_size'] = reduce(lambda x, y: x + y[0].size,
-                                  self._contents.values(), 0)
+                                  list(self._contents.values()), 0)
         # On optimized archives, store the preloaded size and the central
         # directory entries, followed by the first end of central directory.
         if self._optimize:
@@ -570,18 +573,18 @@ class JarWriter(object):
             if preload_size:
                 preload_size += offset
             self._data.write(struct.pack('<I', preload_size))
-            for entry, _ in self._contents.itervalues():
+            for entry, _ in self._contents.values():
                 entry['offset'] += offset
                 self._data.write(entry.serialize())
             self._data.write(end.serialize())
         # Store local file entries followed by compressed data
-        for entry, content in self._contents.itervalues():
+        for entry, content in self._contents.values():
             self._data.write(headers[entry].serialize())
             self._data.write(content)
         # On non optimized archives, store the central directory entries.
         if not self._optimize:
             end['cdir_offset'] = offset
-            for entry, _ in self._contents.itervalues():
+            for entry, _ in self._contents.values():
                 self._data.write(entry.serialize())
         # Store the end of central directory.
         self._data.write(end.serialize())
@@ -621,7 +624,7 @@ class JarWriter(object):
             deflater = data
         else:
             deflater = Deflater(compress, compress_level=self._compress_level)
-            if isinstance(data, basestring):
+            if isinstance(data, str):
                 deflater.write(data)
             elif hasattr(data, 'read'):
                 if hasattr(data, 'seek'):
@@ -637,7 +640,7 @@ class JarWriter(object):
             # 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
diff --git a/python/mozbuild/mozpack/packager/__init__.py b/python/mozbuild/mozpack/packager/__init__.py
index 4c98ec3d33..31c666b03c 100644
--- a/python/mozbuild/mozpack/packager/__init__.py
+++ b/python/mozbuild/mozpack/packager/__init__.py
@@ -2,7 +2,6 @@
 # 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
 
 from mozbuild.preprocessor import Preprocessor
 import re
@@ -20,7 +19,7 @@ import mozpack.path as mozpath
 from collections import deque
 
 
-class Component(object):
+class Component:
     '''
     Class that represents a component in a package manifest.
     '''
@@ -50,7 +49,7 @@ class Component(object):
         '''
         Split [1, 2, 3, 4, 5, 6, 7] into [(1, 2, 3), (4, 5, 6)].
         '''
-        return zip(*[iter(lst)] * 3)
+        return list(zip(*[iter(lst)] * 3))
 
     KEY_VALUE_RE = re.compile(r'''
         \s*                 # optional whitespace.
@@ -100,7 +99,7 @@ class Component(object):
         component = splits[0].strip()
         if not component:
             raise ValueError('No component found')
-        if not re.match('[a-zA-Z0-9_\-]+$', component):
+        if not re.match(r'[a-zA-Z0-9_\-]+$', component):
             raise ValueError('Bad component name ' + component)
         options = Component._split_options(splits[1]) if len(splits) > 1 else {}
         return component, options
@@ -118,11 +117,11 @@ class Component(object):
         destdir = options.pop('destdir', '')
         if options:
             errors.fatal('Malformed manifest: options %s not recognized'
-                         % options.keys())
+                         % list(options.keys()))
         return Component(name, destdir=destdir)
 
 
-class PackageManifestParser(object):
+class PackageManifestParser:
     '''
     Class for parsing of a package manifest, after preprocessing.
 
@@ -166,7 +165,7 @@ class PackageManifestParser(object):
             self._sink.add(self._component, str)
 
 
-class PreprocessorOutputWrapper(object):
+class PreprocessorOutputWrapper:
     '''
     File-like helper to handle the preprocessor output and send it to a parser.
     The parser's handle_line method is called in the relevant errors.context.
@@ -222,7 +221,7 @@ class CallDeque(deque):
                 function(*args)
 
 
-class SimplePackager(object):
+class SimplePackager:
     '''
     Helper used to translate and buffer instructions from the
     SimpleManifestSink to a formatter. Formatters expect some information to be
@@ -267,6 +266,8 @@ class SimplePackager(object):
             if mozpath.basename(path) == 'install.rdf':
                 addon = True
                 install_rdf = file.open().read()
+                if isinstance(install_rdf, bytes):
+                    install_rdf = install_rdf.decode('utf-8', errors='replace')
                 if self.UNPACK_ADDON_RE.search(install_rdf):
                     addon = 'unpacked'
                 self._addons[mozpath.dirname(path)] = addon
@@ -309,9 +310,9 @@ class SimplePackager(object):
         manifests are manifests that are included in no other manifest.
         `addons` indicates whether to include addon bases as well.
         '''
-        all_bases = set(mozpath.dirname(m)
+        all_bases = {mozpath.dirname(m)
                         for m in self._manifests
-                                 - set(self._included_manifests))
+                                 - set(self._included_manifests)}
         if not addons:
             all_bases -= set(self._addons)
         else:
@@ -328,7 +329,7 @@ class SimplePackager(object):
 
         bases = self.get_bases()
         broken_bases = sorted(
-            m for m, includer in self._included_manifests.iteritems()
+            m for m, includer in self._included_manifests.items()
             if mozpath.basedir(m, bases) != mozpath.basedir(includer, bases))
         for m in broken_bases:
             errors.fatal('"%s" is included from "%s", which is outside "%s"' %
@@ -341,7 +342,7 @@ class SimplePackager(object):
         self._file_queue.execute()
 
 
-class SimpleManifestSink(object):
+class SimpleManifestSink:
     '''
     Parser sink for "simple" package manifests. Simple package manifests use
     the format described in the PackageManifestParser documentation, but don't
diff --git a/python/mozbuild/mozpack/packager/formats.py b/python/mozbuild/mozpack/packager/formats.py
index 235fc3e90f..3442945b5f 100644
--- a/python/mozbuild/mozpack/packager/formats.py
+++ b/python/mozbuild/mozpack/packager/formats.py
@@ -2,7 +2,6 @@
 # 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
 
 from mozpack.chrome.manifest import (
     Manifest,
@@ -11,7 +10,7 @@ from mozpack.chrome.manifest import (
     ManifestBinaryComponent,
     ManifestResource,
 )
-from urlparse import urlparse
+from urllib.parse import urlparse
 import mozpack.path as mozpath
 from mozpack.files import (
     ManifestFile,
@@ -67,7 +66,7 @@ data.
 '''
 
 
-class PiecemealFormatter(object):
+class PiecemealFormatter:
     '''
     Generic formatter that dispatches across different sub-formatters
     according to paths.
@@ -89,7 +88,7 @@ class PiecemealFormatter(object):
         Return the deepest base directory containing the given path.
         '''
         self._frozen_bases = True
-        base = mozpath.basedir(path, self._sub_formatter.keys())
+        base = mozpath.basedir(path, list(self._sub_formatter.keys()))
         relpath = mozpath.relpath(path, base) if base else path
         return base, relpath
 
@@ -126,7 +125,7 @@ class FlatFormatter(PiecemealFormatter):
             FileRegistrySubtree(base, self.copier))
 
 
-class FlatSubFormatter(object):
+class FlatSubFormatter:
     '''
     Sub-formatter for the flat package format.
     '''
diff --git a/python/mozbuild/mozpack/packager/l10n.py b/python/mozbuild/mozpack/packager/l10n.py
index e3e05fc894..3604168454 100644
--- a/python/mozbuild/mozpack/packager/l10n.py
+++ b/python/mozbuild/mozpack/packager/l10n.py
@@ -2,7 +2,6 @@
 # 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
 
 '''
 Replace localized parts of a packaged directory with data from a langpack
@@ -42,12 +41,12 @@ from mozpack.packager.unpack import UnpackFinder
 from createprecomplete import generate_precomplete
 
 
-class LocaleManifestFinder(object):
+class LocaleManifestFinder:
     def __init__(self, finder):
         entries = self.entries = []
         bases = self.bases = []
 
-        class MockFormatter(object):
+        class MockFormatter:
             def add_interfaces(self, path, content):
                 pass
 
@@ -66,7 +65,7 @@ class LocaleManifestFinder(object):
         # Those type of entries are used by language packs to work as addons,
         # but are not necessary for the purpose of l10n repacking. So we wrap
         # the finder in order to remove those entries.
-        class WrapFinder(object):
+        class WrapFinder:
             def __init__(self, finder):
                 self._finder = finder
 
@@ -88,8 +87,8 @@ class LocaleManifestFinder(object):
         sink.close(False)
 
         # Find unique locales used in these manifest entries.
-        self.locales = list(set(e.id for e in self.entries
-                                if isinstance(e, ManifestLocale)))
+        self.locales = list({e.id for e in self.entries
+                                if isinstance(e, ManifestLocale)})
 
 
 def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
@@ -140,8 +139,8 @@ def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
     for pattern in non_chrome:
         for base in app.bases:
             path = mozpath.join(base, pattern)
-            left = set(p for p, f in app_finder.find(path))
-            right = set(p for p, f in l10n_finder.find(path))
+            left = {p for p, f in app_finder.find(path)}
+            right = {p for p, f in l10n_finder.find(path)}
             for p in right:
                 paths[p] = p
             for p in left - right:
@@ -163,7 +162,7 @@ def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
             if not path:
                 continue
         else:
-            base = mozpath.basedir(p, paths.keys())
+            base = mozpath.basedir(p, list(paths.keys()))
             if base:
                 subpath = mozpath.relpath(p, base)
                 path = mozpath.normpath(mozpath.join(paths[base],
@@ -184,7 +183,7 @@ def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
 
     # Add localized manifest entries from the langpack.
     l10n_manifests = []
-    for base in set(e.base for e in l10n.entries):
+    for base in {e.base for e in l10n.entries}:
         m = ManifestFile(base, [e for e in l10n.entries if e.base == base])
         path = mozpath.join(base, 'chrome.%s.manifest' % l10n_locale)
         l10n_manifests.append((path, m))
@@ -207,7 +206,7 @@ def _repack(app_finder, l10n_finder, copier, formatter, non_chrome=set()):
                     formatter.add(p, f)
 
     # Transplant jar preloading information.
-    for path, log in app_finder.jarlogs.iteritems():
+    for path, log in app_finder.jarlogs.items():
         assert isinstance(copier[path], Jarrer)
         copier[path].preload([l.replace(locale, l10n_locale) for l in log])
 
@@ -238,7 +237,7 @@ def repack(source, l10n, extra_l10n={}, non_resources=[], non_chrome=set()):
         finders = {
             '': l10n_finder,
         }
-        for base, path in extra_l10n.iteritems():
+        for base, path in extra_l10n.items():
             finders[base] = UnpackFinder(path)
         l10n_finder = ComposedFinder(finders)
     copier = FileCopier()
diff --git a/python/mozbuild/mozpack/packager/unpack.py b/python/mozbuild/mozpack/packager/unpack.py
index 515705c0d7..b28a3fc20a 100644
--- a/python/mozbuild/mozpack/packager/unpack.py
+++ b/python/mozbuild/mozpack/packager/unpack.py
@@ -2,7 +2,6 @@
 # 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 mozpack.path as mozpath
 from mozpack.files import (
@@ -27,7 +26,7 @@ from mozpack.packager.formats import (
     FlatFormatter,
     STARTUP_CACHE_PATHS,
 )
-from urlparse import urlparse
+from urllib.parse import urlparse
 
 
 class UnpackFinder(BaseFinder):
@@ -148,7 +147,7 @@ class UnpackFinder(BaseFinder):
             self.optimizedjars = True
         self.compressed = max(self.compressed, jar.compression)
         if jar.last_preloaded:
-            jarlog = jar.entries.keys()
+            jarlog = list(jar.entries.keys())
             self.jarlogs[path] = jarlog[:jarlog.index(jar.last_preloaded) + 1]
         return jar
 
diff --git a/python/mozbuild/mozpack/path.py b/python/mozbuild/mozpack/path.py
index 7ea8ea85ad..239c226dce 100644
--- a/python/mozbuild/mozpack/path.py
+++ b/python/mozbuild/mozpack/path.py
@@ -2,7 +2,6 @@
 # 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 posixpath
 import os
diff --git a/python/mozbuild/mozpack/test/support/minify_js_verify.py b/python/mozbuild/mozpack/test/support/minify_js_verify.py
index 8e4e8b7590..d4cffb7b3b 100644
--- a/python/mozbuild/mozpack/test/support/minify_js_verify.py
+++ b/python/mozbuild/mozpack/test/support/minify_js_verify.py
@@ -2,7 +2,6 @@
 # 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 print_function
 import sys
 
 
diff --git a/python/mozbuild/mozpack/test/test_archive.py b/python/mozbuild/mozpack/test/test_archive.py
index 6f61f7eb7a..3bad0f56b8 100644
--- a/python/mozbuild/mozpack/test/test_archive.py
+++ b/python/mozbuild/mozpack/test/test_archive.py
@@ -2,7 +2,6 @@
 # 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 hashlib
 import os
@@ -69,7 +68,7 @@ class TestArchive(unittest.TestCase):
         try:
             tp = os.path.join(d, 'test.tar')
             with open(tp, 'wb') as fh:
-                with self.assertRaisesRegexp(ValueError, 'not a regular'):
+                with self.assertRaisesRegex(ValueError, 'not a regular'):
                     create_tar_from_files(fh, {'test': d})
         finally:
             shutil.rmtree(d)
@@ -89,9 +88,9 @@ class TestArchive(unittest.TestCase):
 
             tp = os.path.join(d, 'test.tar')
             with open(tp, 'wb') as fh:
-                with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
+                with self.assertRaisesRegex(ValueError, 'cannot add file with setuid'):
                     create_tar_from_files(fh, {'test': uid})
-                with self.assertRaisesRegexp(ValueError, 'cannot add file with setuid'):
+                with self.assertRaisesRegex(ValueError, 'cannot add file with setuid'):
                     create_tar_from_files(fh, {'test': gid})
         finally:
             shutil.rmtree(d)
diff --git a/python/mozbuild/mozpack/test/test_chrome_manifest.py b/python/mozbuild/mozpack/test/test_chrome_manifest.py
index 690c6acdc9..1ffeba7237 100644
--- a/python/mozbuild/mozpack/test/test_chrome_manifest.py
+++ b/python/mozbuild/mozpack/test/test_chrome_manifest.py
@@ -24,7 +24,7 @@ from mozpack.chrome.manifest import (
     parse_manifest_line,
 )
 from mozpack.errors import errors, AccumulatedErrors
-from test_errors import TestErrors
+from .test_errors import TestErrors
 
 
 class TestManifest(unittest.TestCase):
@@ -91,7 +91,7 @@ class TestManifest(unittest.TestCase):
         with mozunit.MockedOpen({'manifest': '\n'.join(manifest),
                                  'other/manifest': '\n'.join(other_manifest)}):
             # Ensure we have tests for all types of manifests.
-            self.assertEqual(set(type(e) for e in expected_result),
+            self.assertEqual({type(e) for e in expected_result},
                              set(MANIFESTS_TYPES.values()))
             self.assertEqual(list(parse_manifest(os.curdir, 'manifest')),
                              expected_result)
diff --git a/python/mozbuild/mozpack/test/test_copier.py b/python/mozbuild/mozpack/test/test_copier.py
index 6688b3d5ef..06fa34a4d8 100644
--- a/python/mozbuild/mozpack/test/test_copier.py
+++ b/python/mozbuild/mozpack/test/test_copier.py
@@ -127,7 +127,7 @@ class TestFileRegistry(BaseTestFileRegistry, unittest.TestCase):
             'bar': [],
         }
         reg = FileRegistry()
-        for path, parts in cases.iteritems():
+        for path, parts in cases.items():
             self.assertEqual(reg._partial_paths(path), parts)
 
     def test_file_registry(self):
@@ -212,10 +212,10 @@ class TestFileCopier(TestWithTmpDir):
         result = copier.copy(self.tmpdir)
         self.assertEqual(self.all_files(self.tmpdir), set(copier.paths()))
         self.assertEqual(self.all_dirs(self.tmpdir),
-                         set(['foo/deep/nested/directory', 'qux']))
+                         {'foo/deep/nested/directory', 'qux'})
 
-        self.assertEqual(result.updated_files, set(self.tmppath(p) for p in
-            self.all_files(self.tmpdir)))
+        self.assertEqual(result.updated_files, {self.tmppath(p) for p in
+            self.all_files(self.tmpdir)})
         self.assertEqual(result.existing_files, set())
         self.assertEqual(result.removed_files, set())
         self.assertEqual(result.removed_directories, set())
@@ -224,9 +224,9 @@ class TestFileCopier(TestWithTmpDir):
         copier.add('test', GeneratedFile('test'))
         result = copier.copy(self.tmpdir)
         self.assertEqual(self.all_files(self.tmpdir), set(copier.paths()))
-        self.assertEqual(self.all_dirs(self.tmpdir), set(['qux']))
-        self.assertEqual(result.removed_files, set(self.tmppath(p) for p in
-            ('foo/bar', 'foo/qux', 'foo/deep/nested/directory/file')))
+        self.assertEqual(self.all_dirs(self.tmpdir), {'qux'})
+        self.assertEqual(result.removed_files, {self.tmppath(p) for p in
+            ('foo/bar', 'foo/qux', 'foo/deep/nested/directory/file')})
 
     def test_symlink_directory_replaced(self):
         """Directory symlinks in destination are replaced if they need to be
@@ -289,7 +289,7 @@ class TestFileCopier(TestWithTmpDir):
         self.assertFalse(stat.S_ISDIR(st.st_mode))
 
         self.assertEqual(self.all_files(dest), set(copier.paths()))
-        self.assertEqual(self.all_dirs(dest), set(['foo/bar']))
+        self.assertEqual(self.all_dirs(dest), {'foo/bar'})
 
         self.assertEqual(result.removed_directories, set())
         self.assertEqual(len(result.updated_files), 1)
@@ -304,11 +304,11 @@ class TestFileCopier(TestWithTmpDir):
         self.assertFalse(stat.S_ISLNK(st.st_mode))
         self.assertTrue(stat.S_ISDIR(st.st_mode))
 
-        self.assertEqual(result.removed_files, set([link]))
+        self.assertEqual(result.removed_files, {link})
         self.assertEqual(result.removed_directories, set())
 
         self.assertEqual(self.all_files(dest), set(copier.paths()))
-        self.assertEqual(self.all_dirs(dest), set(['foo/bar', 'zot']))
+        self.assertEqual(self.all_dirs(dest), {'foo/bar', 'zot'})
 
         # If remove_unaccounted and remove_empty_directories, then
         # both the symlink and its containing directory are removed.
@@ -319,11 +319,11 @@ class TestFileCopier(TestWithTmpDir):
             remove_empty_directories=True,
             remove_all_directory_symlinks=False)
 
-        self.assertEqual(result.removed_files, set([link]))
-        self.assertEqual(result.removed_directories, set([self.tmppath('dest/zot')]))
+        self.assertEqual(result.removed_files, {link})
+        self.assertEqual(result.removed_directories, {self.tmppath('dest/zot')})
 
         self.assertEqual(self.all_files(dest), set(copier.paths()))
-        self.assertEqual(self.all_dirs(dest), set(['foo/bar']))
+        self.assertEqual(self.all_dirs(dest), {'foo/bar'})
 
     def test_permissions(self):
         """Ensure files without write permission can be deleted."""
@@ -362,12 +362,12 @@ class TestFileCopier(TestWithTmpDir):
 
         result = copier.copy(self.tmpdir, remove_unaccounted=False)
 
-        self.assertEqual(self.all_files(self.tmpdir), set(['foo', 'bar',
-            'populateddir/foo']))
-        self.assertEqual(self.all_dirs(self.tmpdir), set(['populateddir']))
+        self.assertEqual(self.all_files(self.tmpdir), {'foo', 'bar',
+            'populateddir/foo'})
+        self.assertEqual(self.all_dirs(self.tmpdir), {'populateddir'})
         self.assertEqual(result.removed_files, set())
         self.assertEqual(result.removed_directories,
-            set([self.tmppath('emptydir')]))
+            {self.tmppath('emptydir')})
 
     def test_no_remove_empty_directories(self):
         copier = FileCopier()
@@ -386,10 +386,10 @@ class TestFileCopier(TestWithTmpDir):
         result = copier.copy(self.tmpdir, remove_unaccounted=False,
             remove_empty_directories=False)
 
-        self.assertEqual(self.all_files(self.tmpdir), set(['foo', 'bar',
-            'populateddir/foo']))
-        self.assertEqual(self.all_dirs(self.tmpdir), set(['emptydir',
-            'populateddir']))
+        self.assertEqual(self.all_files(self.tmpdir), {'foo', 'bar',
+            'populateddir/foo'})
+        self.assertEqual(self.all_dirs(self.tmpdir), {'emptydir',
+            'populateddir'})
         self.assertEqual(result.removed_files, set())
         self.assertEqual(result.removed_directories, set())
 
@@ -414,7 +414,7 @@ class TestFileCopier(TestWithTmpDir):
         self.assertTrue(stat.S_ISDIR(st.st_mode))
 
         # What's worse, we have no record that dest was created.
-        self.assertEquals(len(result.updated_files), 0)
+        self.assertEqual(len(result.updated_files), 0)
 
         # But we do have an erroneous record of an optional file
         # existing when it does not.
diff --git a/python/mozbuild/mozpack/test/test_errors.py b/python/mozbuild/mozpack/test/test_errors.py
index 16e2b04964..ecd0e1b808 100644
--- a/python/mozbuild/mozpack/test/test_errors.py
+++ b/python/mozbuild/mozpack/test/test_errors.py
@@ -13,7 +13,7 @@ import sys
 from cStringIO import StringIO
 
 
-class TestErrors(object):
+class TestErrors:
     def setUp(self):
         errors.out = StringIO()
         errors.ignore_errors(False)
@@ -30,14 +30,14 @@ class TestErrorsImpl(TestErrors, unittest.TestCase):
         errors.warn('foo')
         self.assertRaises(ErrorMessage, errors.error, 'foo')
         self.assertRaises(ErrorMessage, errors.fatal, 'foo')
-        self.assertEquals(self.get_output(), ['Warning: foo'])
+        self.assertEqual(self.get_output(), ['Warning: foo'])
 
     def test_ignore_errors(self):
         errors.ignore_errors()
         errors.warn('foo')
         errors.error('bar')
         self.assertRaises(ErrorMessage, errors.fatal, 'foo')
-        self.assertEquals(self.get_output(), ['Warning: foo', 'Warning: bar'])
+        self.assertEqual(self.get_output(), ['Warning: foo', 'Warning: bar'])
 
     def test_no_error(self):
         with errors.accumulate():
@@ -47,14 +47,14 @@ class TestErrorsImpl(TestErrors, unittest.TestCase):
         with self.assertRaises(AccumulatedErrors):
             with errors.accumulate():
                 errors.error('1')
-        self.assertEquals(self.get_output(), ['Error: 1'])
+        self.assertEqual(self.get_output(), ['Error: 1'])
 
     def test_error_loop(self):
         with self.assertRaises(AccumulatedErrors):
             with errors.accumulate():
                 for i in range(3):
                     errors.error('%d' % i)
-        self.assertEquals(self.get_output(),
+        self.assertEqual(self.get_output(),
                           ['Error: 0', 'Error: 1', 'Error: 2'])
 
     def test_multiple_errors(self):
@@ -67,7 +67,7 @@ class TestErrorsImpl(TestErrors, unittest.TestCase):
                     else:
                         errors.error('%d' % i)
                 errors.error('bar')
-        self.assertEquals(self.get_output(),
+        self.assertEqual(self.get_output(),
                           ['Error: foo', 'Error: 0', 'Error: 1',
                            'Warning: 2', 'Error: bar'])
 
diff --git a/python/mozbuild/mozpack/test/test_files.py b/python/mozbuild/mozpack/test/test_files.py
index 6fd6178288..260a458805 100644
--- a/python/mozbuild/mozpack/test/test_files.py
+++ b/python/mozbuild/mozpack/test/test_files.py
@@ -81,7 +81,7 @@ class TestWithTmpDir(unittest.TestCase):
         try:
             os.symlink(dummy_path, self.tmppath('dummy_symlink'))
             os.remove(self.tmppath('dummy_symlink'))
-        except EnvironmentError:
+        except OSError:
             pass
         finally:
             os.remove(dummy_path)
@@ -146,7 +146,7 @@ class TestDest(TestWithTmpDir):
         dest.write('qux')
         self.assertEqual(dest.read(), 'qux')
 
-rand = ''.join(random.choice(string.letters) for i in xrange(131597))
+rand = ''.join(random.choice(string.letters) for i in range(131597))
 samples = [
     '',
     'test',
@@ -268,12 +268,12 @@ class TestAbsoluteSymlinkFile(TestWithTmpDir):
     def test_absolute_relative(self):
         AbsoluteSymlinkFile('/foo')
 
-        with self.assertRaisesRegexp(ValueError, 'Symlink target not absolute'):
+        with self.assertRaisesRegex(ValueError, 'Symlink target not absolute'):
             AbsoluteSymlinkFile('./foo')
 
     def test_symlink_file(self):
         source = self.tmppath('test_path')
-        with open(source, 'wt') as fh:
+        with open(source, 'w') as fh:
             fh.write('Hello world')
 
         s = AbsoluteSymlinkFile(source)
@@ -293,7 +293,7 @@ class TestAbsoluteSymlinkFile(TestWithTmpDir):
         # If symlinks are supported, an existing file should be replaced by a
         # symlink.
         source = self.tmppath('test_path')
-        with open(source, 'wt') as fh:
+        with open(source, 'w') as fh:
             fh.write('source')
 
         dest = self.tmppath('dest')
@@ -477,7 +477,7 @@ class TestPreprocessedFile(TestWithTmpDir):
 
 class TestExistingFile(TestWithTmpDir):
     def test_required_missing_dest(self):
-        with self.assertRaisesRegexp(ErrorMessage, 'Required existing file'):
+        with self.assertRaisesRegex(ErrorMessage, 'Required existing file'):
             f = ExistingFile(required=True)
             f.copy(self.tmppath('dest'))
 
@@ -566,7 +566,7 @@ class TestDeflatedFile(TestWithTmpDir):
         with JarWriter(src) as jar:
             for content in samples:
                 name = ''.join(random.choice(string.letters)
-                               for i in xrange(8))
+                               for i in range(8))
                 jar.add(name, content, compress=True)
                 contents[name] = content
 
@@ -718,7 +718,7 @@ foo2_xpt = GeneratedFile(
 
 
 def read_interfaces(file):
-    return dict((i.name, i) for i in Typelib.read(file).interfaces)
+    return {i.name: i for i in Typelib.read(file).interfaces}
 
 
 class TestXPTFile(TestWithTmpDir):
@@ -830,7 +830,7 @@ class TestMinifiedJavaScript(TestWithTmpDir):
         self.assertEqual(mini_lines, orig_f.open().readlines())
 
 
-class MatchTestTemplate(object):
+class MatchTestTemplate:
     def prepare_match_test(self, with_dotfiles=False):
         self.add('bar')
         self.add('foo/bar')
@@ -1072,7 +1072,7 @@ class TestComposedFinder(MatchTestTemplate, TestWithTmpDir):
 @unittest.skipUnless(hglib, 'hglib not available')
 class TestMercurialRevisionFinder(MatchTestTemplate, TestWithTmpDir):
     def setUp(self):
-        super(TestMercurialRevisionFinder, self).setUp()
+        super().setUp()
         hglib.init(self.tmpdir)
 
     def add(self, path):
diff --git a/python/mozbuild/mozpack/test/test_manifests.py b/python/mozbuild/mozpack/test/test_manifests.py
index 7d926a0c8a..3171e04f4b 100644
--- a/python/mozbuild/mozpack/test/test_manifests.py
+++ b/python/mozbuild/mozpack/test/test_manifests.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 
@@ -187,13 +186,13 @@ class TestInstallManifest(TestWithTmpDir):
         with open(to_delete, 'a'):
             pass
 
-        with open(self.tmppath('s_source'), 'wt') as fh:
+        with open(self.tmppath('s_source'), 'w') as fh:
             fh.write('symlink!')
 
-        with open(self.tmppath('c_source'), 'wt') as fh:
+        with open(self.tmppath('c_source'), 'w') as fh:
             fh.write('copy!')
 
-        with open(self.tmppath('p_source'), 'wt') as fh:
+        with open(self.tmppath('p_source'), 'w') as fh:
             fh.write('#define FOO 1\npreprocess!')
 
         with open(self.tmppath('dest/e_dest'), 'a'):
@@ -215,19 +214,19 @@ class TestInstallManifest(TestWithTmpDir):
         self.assertTrue(os.path.exists(self.tmppath('dest/content')))
         self.assertFalse(os.path.exists(to_delete))
 
-        with open(self.tmppath('dest/s_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/s_dest')) as fh:
             self.assertEqual(fh.read(), 'symlink!')
 
-        with open(self.tmppath('dest/c_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/c_dest')) as fh:
             self.assertEqual(fh.read(), 'copy!')
 
-        with open(self.tmppath('dest/p_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/p_dest')) as fh:
             self.assertEqual(fh.read(), 'preprocess!')
 
-        self.assertEqual(result.updated_files, set(self.tmppath(p) for p in (
-            'dest/s_dest', 'dest/c_dest', 'dest/p_dest', 'dest/content')))
+        self.assertEqual(result.updated_files, {self.tmppath(p) for p in (
+            'dest/s_dest', 'dest/c_dest', 'dest/p_dest', 'dest/content')})
         self.assertEqual(result.existing_files,
-            set([self.tmppath('dest/e_dest'), self.tmppath('dest/o_dest')]))
+            {self.tmppath('dest/e_dest'), self.tmppath('dest/o_dest')})
         self.assertEqual(result.removed_files, {to_delete})
         self.assertEqual(result.removed_directories, set())
 
@@ -237,12 +236,12 @@ class TestInstallManifest(TestWithTmpDir):
         dest = self.tmppath('dest')
         include = self.tmppath('p_incl')
 
-        with open(include, 'wt') as fh:
+        with open(include, 'w') as fh:
             fh.write('#define INCL\n')
         time = os.path.getmtime(include) - 3
         os.utime(include, (time, time))
 
-        with open(self.tmppath('p_source'), 'wt') as fh:
+        with open(self.tmppath('p_source'), 'w') as fh:
             fh.write('#ifdef FOO\n#if BAZ == QUX\nPASS1\n#endif\n#endif\n')
             fh.write('#ifdef DEPTEST\nPASS2\n#endif\n')
             fh.write('#include p_incl\n#ifdef INCLTEST\nPASS3\n#endif\n')
@@ -262,7 +261,7 @@ class TestInstallManifest(TestWithTmpDir):
 
         self.assertTrue(os.path.exists(self.tmppath('dest/p_dest')))
 
-        with open(self.tmppath('dest/p_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/p_dest')) as fh:
             self.assertEqual(fh.read(), 'PASS1\n')
 
         # Create a second manifest with the preprocessed file, then apply it.
@@ -290,7 +289,7 @@ class TestInstallManifest(TestWithTmpDir):
         m2.populate_registry(c)
         self.assertTrue(c.copy(dest))
 
-        with open(self.tmppath('dest/p_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/p_dest')) as fh:
             self.assertEqual(fh.read(), 'PASS2\n')
 
         # Set the time on the manifest back, so it won't be picked up as
@@ -300,7 +299,7 @@ class TestInstallManifest(TestWithTmpDir):
 
         # Update the contents of a file included by the source file. This should
         # cause the destination to be regenerated.
-        with open(include, 'wt') as fh:
+        with open(include, 'w') as fh:
             fh.write('#define INCLTEST\n')
 
         time = os.path.getmtime(include) - 1
@@ -309,7 +308,7 @@ class TestInstallManifest(TestWithTmpDir):
         m2.populate_registry(c)
         self.assertTrue(c.copy(dest))
 
-        with open(self.tmppath('dest/p_dest'), 'rt') as fh:
+        with open(self.tmppath('dest/p_dest')) as fh:
             self.assertEqual(fh.read(), 'PASS2\nPASS3\n')
 
     def test_preprocessor_dependencies(self):
@@ -321,12 +320,12 @@ class TestInstallManifest(TestWithTmpDir):
         include = self.tmppath('p_incl')
         os.mkdir(dest)
 
-        with open(source, 'wt') as fh:
+        with open(source, 'w') as fh:
             fh.write('#define SRC\nSOURCE\n')
         time = os.path.getmtime(source) - 3
         os.utime(source, (time, time))
 
-        with open(include, 'wt') as fh:
+        with open(include, 'w') as fh:
             fh.write('INCLUDE\n')
         time = os.path.getmtime(source) - 3
         os.utime(include, (time, time))
@@ -346,11 +345,11 @@ class TestInstallManifest(TestWithTmpDir):
         m.populate_registry(c)
         self.assertTrue(c.copy(dest))
 
-        with open(destfile, 'rt') as fh:
+        with open(destfile) as fh:
             self.assertEqual(fh.read(), 'SOURCE\n')
 
         # Next, modify the source to #INCLUDE another file.
-        with open(source, 'wt') as fh:
+        with open(source, 'w') as fh:
             fh.write('SOURCE\n#include p_incl\n')
         time = os.path.getmtime(source) - 1
         os.utime(destfile, (time, time))
@@ -362,7 +361,7 @@ class TestInstallManifest(TestWithTmpDir):
         m.populate_registry(c)
         c.copy(dest)
 
-        with open(destfile, 'rt') as fh:
+        with open(destfile) as fh:
             self.assertEqual(fh.read(), 'SOURCE\nINCLUDE\n')
 
         # Set the time on the source file back, so it won't be picked up as
@@ -371,7 +370,7 @@ class TestInstallManifest(TestWithTmpDir):
         os.utime(source, (time, time))
 
         # Now, modify the include file (but not the original source).
-        with open(include, 'wt') as fh:
+        with open(include, 'w') as fh:
             fh.write('INCLUDE MODIFIED\n')
         time = os.path.getmtime(include) - 1
         os.utime(destfile, (time, time))
@@ -383,7 +382,7 @@ class TestInstallManifest(TestWithTmpDir):
         m.populate_registry(c)
         c.copy(dest)
 
-        with open(destfile, 'rt') as fh:
+        with open(destfile) as fh:
             self.assertEqual(fh.read(), 'SOURCE\nINCLUDE MODIFIED\n')
 
         # ORing an InstallManifest should copy file dependencies
diff --git a/python/mozbuild/mozpack/test/test_mozjar.py b/python/mozbuild/mozpack/test/test_mozjar.py
index 9484030069..063bdfc244 100644
--- a/python/mozbuild/mozpack/test/test_mozjar.py
+++ b/python/mozbuild/mozpack/test/test_mozjar.py
@@ -17,7 +17,7 @@ from mozpack.test.test_files import MockDest
 import unittest
 import mozunit
 from cStringIO import StringIO
-from urllib import pathname2url
+from urllib.request import pathname2url
 import mozpack.path as mozpath
 import os
 
@@ -310,12 +310,12 @@ class TestJarLog(unittest.TestCase):
             mozpath.normsep(os.path.normcase(os.path.realpath(p)))
         baz_jar = canonicalize('bar/baz.jar')
         qux_zip = canonicalize('qux.zip')
-        self.assertEqual(set(log.keys()), set([
+        self.assertEqual(set(log.keys()), {
             baz_jar,
             (qux_zip, 'omni.ja'),
             (qux_zip, 'baz/baz.jar', 'omni.ja'),
             (qux_zip, 'baz/baz.jar', 'foo.zip', 'omni.ja'),
-        ]))
+        })
         self.assertEqual(log[baz_jar], [
             'first',
             'second',
diff --git a/python/mozbuild/mozpack/test/test_packager.py b/python/mozbuild/mozpack/test/test_packager.py
index 397f405386..97db960154 100644
--- a/python/mozbuild/mozpack/test/test_packager.py
+++ b/python/mozbuild/mozpack/test/test_packager.py
@@ -54,7 +54,7 @@ class TestPreprocessManifest(unittest.TestCase):
     ]
 
     def setUp(self):
-        class MockSink(object):
+        class MockSink:
             def __init__(self):
                 self.log = []
 
@@ -92,7 +92,7 @@ class TestPreprocessManifest(unittest.TestCase):
                          [((self.MANIFEST_PATH, 12), 'add', 'baz', 'baz.exe')])
 
 
-class MockFinder(object):
+class MockFinder:
     def __init__(self, files):
         self.files = files
         self.log = []
@@ -107,7 +107,7 @@ class MockFinder(object):
         return self.find('')
 
 
-class MockFormatter(object):
+class MockFormatter:
     def __init__(self):
         self.log = []
 
@@ -300,10 +300,10 @@ class TestSimplePackager(unittest.TestCase):
         ])
 
         self.assertEqual(packager.get_bases(),
-                         set(['', 'addon', 'addon2', 'addon3', 'addon4',
+                         {'', 'addon', 'addon2', 'addon3', 'addon4',
                               'addon5', 'addon6', 'addon7', 'addon8',
-                              'addon9', 'addon10', 'addon11', 'qux']))
-        self.assertEqual(packager.get_bases(addons=False), set(['', 'qux']))
+                              'addon9', 'addon10', 'addon11', 'qux'})
+        self.assertEqual(packager.get_bases(addons=False), {'', 'qux'})
 
     def test_simple_packager_manifest_consistency(self):
         formatter = MockFormatter()
@@ -408,7 +408,7 @@ class TestSimpleManifestSink(unittest.TestCase):
 
 class TestCallDeque(unittest.TestCase):
     def test_call_deque(self):
-        class Logger(object):
+        class Logger:
             def __init__(self):
                 self._log = []
 
diff --git a/python/mozbuild/mozpack/test/test_packager_formats.py b/python/mozbuild/mozpack/test/test_packager_formats.py
index 4ba61e880f..06f7c5942b 100644
--- a/python/mozbuild/mozpack/test/test_packager_formats.py
+++ b/python/mozbuild/mozpack/test/test_packager_formats.py
@@ -120,7 +120,7 @@ for addon in ('addon0', 'addon1'):
             'chrome/chrome.manifest': [
                 'content content foo/bar/',
             ],
-            'chrome/foo/bar/baz': FILES[mozpath.join(addon, 'chrome/foo/bar/baz')],
+            'chrome/foo/bar/baz': FILES[mozpath.join(addon, 'chrome/foo/bar/baz'.items()],
             'components/components.manifest': [
                 'interfaces interfaces.xpt',
             ],
@@ -128,7 +128,7 @@ for addon in ('addon0', 'addon1'):
                 'foo': read_interfaces(foo2_xpt.open())['foo'],
                 'bar': read_interfaces(bar_xpt.open())['bar'],
             },
-        }.iteritems()
+        })
     })
 
 RESULT_JAR = {
@@ -174,7 +174,7 @@ RESULT_JAR.update({
     },
     'addon1.xpi': {
         mozpath.relpath(p, 'addon1'): f
-        for p, f in RESULT_FLAT.iteritems()
+        for p, f in RESULT_FLAT.items()
         if p.startswith('addon1/')
     },
 })
@@ -234,7 +234,7 @@ RESULT_OMNIJAR['omni.foo'].update({
 CONTENTS_WITH_BASE = {
     'bases': {
         mozpath.join('base/root', b) if b else 'base/root': a
-        for b, a in CONTENTS['bases'].iteritems()
+        for b, a in CONTENTS['bases'].items()
     },
     'manifests': [
         m.move(mozpath.join('base/root', m.base))
@@ -242,7 +242,7 @@ CONTENTS_WITH_BASE = {
     ],
     'files': {
         mozpath.join('base/root', p): f
-        for p, f in CONTENTS['files'].iteritems()
+        for p, f in CONTENTS['files'].items()
     },
 }
 
@@ -255,7 +255,7 @@ CONTENTS_WITH_BASE['files'].update(EXTRA_CONTENTS)
 def result_with_base(results):
     result = {
         mozpath.join('base/root', p): v
-        for p, v in results.iteritems()
+        for p, v in results.items()
     }
     result.update(EXTRA_CONTENTS)
     return result
@@ -277,7 +277,7 @@ def fill_formatter(formatter, contents):
     for manifest in contents['manifests']:
         formatter.add_manifest(manifest)
 
-    for k, v in contents['files'].iteritems():
+    for k, v in contents['files'].items():
         if k.endswith('.xpt'):
             formatter.add_interfaces(k, v)
         else:
diff --git a/python/mozbuild/mozpack/test/test_packager_l10n.py b/python/mozbuild/mozpack/test/test_packager_l10n.py
index c797eadd17..17d95ec893 100644
--- a/python/mozbuild/mozpack/test/test_packager_l10n.py
+++ b/python/mozbuild/mozpack/test/test_packager_l10n.py
@@ -4,7 +4,7 @@
 
 import unittest
 import mozunit
-from test_packager import MockFinder
+from .test_packager import MockFinder
 from mozpack.packager import l10n
 from mozpack.files import (
     GeneratedFile,
@@ -117,8 +117,8 @@ class TestL10NRepack(unittest.TestCase):
         }
 
         self.assertEqual(
-            dict((p, f.open().read()) for p, f in copier),
-            dict((p, f.open().read()) for p, f in repacked.iteritems())
+            {p: f.open().read() for p, f in copier},
+            {p: f.open().read() for p, f in repacked.items()}
         )
 
 
diff --git a/python/mozbuild/mozpack/test/test_packager_unpack.py b/python/mozbuild/mozpack/test/test_packager_unpack.py
index d201cabf74..913cf63c30 100644
--- a/python/mozbuild/mozpack/test/test_packager_unpack.py
+++ b/python/mozbuild/mozpack/test/test_packager_unpack.py
@@ -56,7 +56,7 @@ class TestUnpack(TestWithTmpDir):
     def test_omnijar_unpack(self):
         class OmniFooFormatter(OmniJarFormatter):
             def __init__(self, registry):
-                super(OmniFooFormatter, self).__init__(registry, 'omni.foo')
+                super().__init__(registry, 'omni.foo')
 
         self._unpack_test(OmniFooFormatter)
 
diff --git a/python/mozbuild/mozpack/test/test_unify.py b/python/mozbuild/mozpack/test/test_unify.py
index a2bbb44702..52f3f46b42 100644
--- a/python/mozbuild/mozpack/test/test_unify.py
+++ b/python/mozbuild/mozpack/test/test_unify.py
@@ -186,7 +186,7 @@ class TestUnifiedBuildFinder(TestUnified):
             # Now create the files from the above table and compare
             results = []
             for emid, (rdf_a, rdf_b, result) in enumerate(testcases):
-                filename = 'ext/id{0}/install.rdf'.format(emid)
+                filename = 'ext/id{}/install.rdf'.format(emid)
                 self.create_one('a', filename, rdf_a)
                 self.create_one('b', filename, rdf_b)
                 results.append((filename, result))
diff --git a/python/mozbuild/mozpack/unify.py b/python/mozbuild/mozpack/unify.py
index 3c8a8d6057..9dd63c4622 100644
--- a/python/mozbuild/mozpack/unify.py
+++ b/python/mozbuild/mozpack/unify.py
@@ -2,7 +2,6 @@
 # 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
 
 from mozpack.files import (
     BaseFinder,
@@ -73,7 +72,7 @@ class UnifiedExecutableFile(BaseFile):
         creating the instance.
         skip_if_older is ignored.
         '''
-        assert isinstance(dest, basestring)
+        assert isinstance(dest, str)
         tmpfiles = []
         try:
             for e in self._executables:
@@ -137,7 +136,7 @@ class UnifiedFinder(BaseFinder):
                 errors.error('File missing in %s: %s' %
                              (self._finder1.base, p))
         for p in [p for p in files1 if not p in files2]:
-            errors.error('File missing in %s: %s' % (self._finder2.base, p))
+            errors.error('File missing in {}: {}'.format(self._finder2.base, p))
 
     def _report_difference(self, path, file1, file2):
         '''
diff --git a/python/mozlint/mozlint/cli.py b/python/mozlint/mozlint/cli.py
index 2a35064ed4..55efda5b5e 100644
--- a/python/mozlint/mozlint/cli.py
+++ b/python/mozlint/mozlint/cli.py
@@ -2,8 +2,8 @@
 # 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 print_function, unicode_literals
 
+from __future__ import print_function
 import os
 import sys
 from argparse import ArgumentParser, REMAINDER
@@ -105,7 +105,7 @@ def run(paths, linters, fmt, rev, workdir, **lintargs):
     # Explicitly utf-8 encode the output as some of the formatters make
     # use of unicode characters. This will prevent a UnicodeEncodeError
     # on environments where utf-8 isn't the default
-    print(formatter(results).encode('utf-8', 'replace'))
+    print((formatter(results).encode('utf-8', 'replace')))
     return lint.return_code
 
 
diff --git a/python/mozlint/mozlint/formatters/__init__.py b/python/mozlint/mozlint/formatters/__init__.py
index 33aca0446d..2650c6e015 100644
--- a/python/mozlint/mozlint/formatters/__init__.py
+++ b/python/mozlint/mozlint/formatters/__init__.py
@@ -9,7 +9,7 @@ from .stylish import StylishFormatter
 from .treeherder import TreeherderFormatter
 
 
-class JSONFormatter(object):
+class JSONFormatter:
     def __call__(self, results):
         return json.dumps(results, cls=ResultEncoder)
 
diff --git a/python/mozlint/mozlint/formatters/stylish.py b/python/mozlint/mozlint/formatters/stylish.py
index 62ddfbeb6a..8ec942fae0 100644
--- a/python/mozlint/mozlint/formatters/stylish.py
+++ b/python/mozlint/mozlint/formatters/stylish.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from ..result import ResultContainer
 
@@ -12,24 +11,24 @@ except ImportError:
     blessings = None
 
 
-class NullTerminal(object):
+class NullTerminal:
     """Replacement for `blessings.Terminal()` that does no formatting."""
-    class NullCallableString(unicode):
+    class NullCallableString(str):
         """A dummy callable Unicode stolen from blessings"""
         def __new__(cls):
-            new = unicode.__new__(cls, u'')
+            new = str.__new__(cls, '')
             return new
 
         def __call__(self, *args):
             if len(args) != 1 or isinstance(args[0], int):
-                return u''
+                return ''
             return args[0]
 
     def __getattr__(self, attr):
         return self.NullCallableString()
 
 
-class StylishFormatter(object):
+class StylishFormatter:
     """Formatter based on the eslint default."""
 
     # Colors later on in the list are fallbacks in case the terminal
@@ -82,7 +81,7 @@ class StylishFormatter(object):
 
         num_errors = 0
         num_warnings = 0
-        for path, errors in sorted(result.iteritems()):
+        for path, errors in sorted(result.items()):
             self._reset_max()
 
             message.append(self.term.underline(path))
diff --git a/python/mozlint/mozlint/formatters/treeherder.py b/python/mozlint/mozlint/formatters/treeherder.py
index 7c27011cf4..80b89ff286 100644
--- a/python/mozlint/mozlint/formatters/treeherder.py
+++ b/python/mozlint/mozlint/formatters/treeherder.py
@@ -2,12 +2,11 @@
 # 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 unicode_literals
 
 from ..result import ResultContainer
 
 
-class TreeherderFormatter(object):
+class TreeherderFormatter:
     """Formatter for treeherder friendly output.
 
     This formatter looks ugly, but prints output such that
@@ -18,7 +17,7 @@ class TreeherderFormatter(object):
 
     def __call__(self, result):
         message = []
-        for path, errors in sorted(result.iteritems()):
+        for path, errors in sorted(result.items()):
             for err in errors:
                 assert isinstance(err, ResultContainer)
 
diff --git a/python/mozlint/mozlint/parser.py b/python/mozlint/mozlint/parser.py
index f350d0de75..9d54d98e4c 100644
--- a/python/mozlint/mozlint/parser.py
+++ b/python/mozlint/mozlint/parser.py
@@ -11,7 +11,7 @@ from .types import supported_types
 from .errors import LinterNotFound, LinterParseError
 
 
-class Parser(object):
+class Parser:
     """Reads and validates `.lint` files."""
     required_attributes = (
         'name',
@@ -63,7 +63,7 @@ class Parser(object):
 
         for attr in ('include', 'exclude'):
             if attr in linter and (not isinstance(linter[attr], list) or
-                                   not all(isinstance(a, basestring) for a in linter[attr])):
+                                   not all(isinstance(a, str) for a in linter[attr])):
                 raise LinterParseError(linter['path'], "The {} directive must be a "
                                                        "list of strings!".format(attr))
 
diff --git a/python/mozlint/mozlint/pathutils.py b/python/mozlint/mozlint/pathutils.py
index 532904dca7..cf79d58150 100644
--- a/python/mozlint/mozlint/pathutils.py
+++ b/python/mozlint/mozlint/pathutils.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 
@@ -10,7 +9,7 @@ from mozpack import path as mozpath
 from mozpack.files import FileFinder
 
 
-class FilterPath(object):
+class FilterPath:
     """Helper class to make comparing and matching file paths easier."""
     def __init__(self, path, exclude=None):
         self.path = os.path.normpath(path)
@@ -86,8 +85,8 @@ def filterpaths(paths, linter, **lintargs):
             path = os.path.join(root, path)
         return FilterPath(path)
 
-    include = map(normalize, include)
-    exclude = map(normalize, exclude)
+    include = list(map(normalize, include))
+    exclude = list(map(normalize, exclude))
 
     # Paths with and without globs will be handled separately,
     # pull them apart now.
diff --git a/python/mozlint/mozlint/result.py b/python/mozlint/mozlint/result.py
index 0c56f1d761..490b2eefc5 100644
--- a/python/mozlint/mozlint/result.py
+++ b/python/mozlint/mozlint/result.py
@@ -5,7 +5,7 @@
 from json import dumps, JSONEncoder
 
 
-class ResultContainer(object):
+class ResultContainer:
     """Represents a single lint error and its related metadata.
 
     :param linter: name of the linter that flagged this error
diff --git a/python/mozlint/mozlint/roller.py b/python/mozlint/mozlint/roller.py
index 2d1608dd87..6cb00da7d5 100644
--- a/python/mozlint/mozlint/roller.py
+++ b/python/mozlint/mozlint/roller.py
@@ -2,14 +2,13 @@
 # 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 unicode_literals
 
 import os
 import signal
 import sys
 import traceback
 from collections import defaultdict
-from Queue import Empty
+from queue import Empty
 from multiprocessing import (
     Manager,
     Pool,
@@ -35,7 +34,7 @@ def _run_linters(queue, paths, **lintargs):
             # also received SIGINT. By the time the worker gets back here, the
             # Queue is dead and IOError is raised.
             linter_path = queue.get(False)
-        except (Empty, IOError):
+        except (Empty, OSError):
             return results, return_code
 
         # Ideally we would pass the entire LINTER definition as an argument
@@ -67,7 +66,7 @@ def _run_worker(*args, **lintargs):
         sys.stdout.flush()
 
 
-class LintRoller(object):
+class LintRoller:
     """Registers and runs linters.
 
     :param root: Path to which relative paths will be joined. If
@@ -91,7 +90,7 @@ class LintRoller(object):
 
         :param paths: A path or iterable of paths to linter definitions.
         """
-        if isinstance(paths, basestring):
+        if isinstance(paths, str):
             paths = (paths,)
 
         for path in paths:
@@ -108,7 +107,7 @@ class LintRoller(object):
                  :class:`~result.ResultContainer`s as the value.
         """
         paths = paths or []
-        if isinstance(paths, basestring):
+        if isinstance(paths, str):
             paths = [paths]
 
         if not self.linters:
@@ -120,7 +119,7 @@ class LintRoller(object):
         if workdir:
             paths.extend(self.vcs.by_workdir())
         paths = paths or ['.']
-        paths = map(os.path.abspath, paths)
+        paths = list(map(os.path.abspath, paths))
 
         # Set up multiprocessing
         m = Manager()
@@ -149,6 +148,6 @@ class LintRoller(object):
             results, return_code = worker.get()
             if results or return_code:
                 self.return_code = 1
-            for k, v in results.iteritems():
+            for k, v in results.items():
                 all_results[k].extend(v)
         return all_results
diff --git a/python/mozlint/mozlint/types.py b/python/mozlint/mozlint/types.py
index 2f49ae2bf2..064b5d595e 100644
--- a/python/mozlint/mozlint/types.py
+++ b/python/mozlint/mozlint/types.py
@@ -2,8 +2,8 @@
 # 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 unicode_literals
 
+from __future__ import print_function
 import re
 import sys
 from abc import ABCMeta, abstractmethod
@@ -13,11 +13,11 @@ from mozlog.reader import LogHandler
 
 from . import result
 from .pathutils import filterpaths
+import six
 
 
-class BaseType(object):
+class BaseType(six.with_metaclass(ABCMeta)):
     """Abstract base class for all types of linters."""
-    __metaclass__ = ABCMeta
     batch = False
 
     def __call__(self, paths, linter, **lintargs):
@@ -31,7 +31,7 @@ class BaseType(object):
         """
         paths = filterpaths(paths, linter, **lintargs)
         if not paths:
-            print("{}: no files to lint in specified paths".format(linter['name']))
+            print(("{}: no files to lint in specified paths".format(linter['name'])))
             return
 
         if self.batch:
@@ -52,13 +52,12 @@ class BaseType(object):
         pass
 
 
-class LineType(BaseType):
+class LineType(six.with_metaclass(ABCMeta, BaseType)):
     """Abstract base class for linter types that check each line individually.
 
     Subclasses of this linter type will read each file and check the provided
     payload against each line one by one.
     """
-    __metaclass__ = ABCMeta
 
     @abstractmethod
     def condition(payload, line):
@@ -67,7 +66,7 @@ class LineType(BaseType):
     def _lint(self, path, linter, **lintargs):
         payload = linter['payload']
 
-        with open(path, 'r') as fh:
+        with open(path) as fh:
             lines = fh.readlines()
 
         errors = []
diff --git a/python/mozlint/mozlint/vcs.py b/python/mozlint/mozlint/vcs.py
index 6a118f2e6a..b7d02e4c3d 100644
--- a/python/mozlint/mozlint/vcs.py
+++ b/python/mozlint/mozlint/vcs.py
@@ -6,7 +6,7 @@ import os
 import subprocess
 
 
-class VCSFiles(object):
+class VCSFiles:
     def __init__(self):
         self._root = None
         self._vcs = None
diff --git a/python/mozlint/test/test_formatters.py b/python/mozlint/test/test_formatters.py
index b9e6512b24..e1ecdba0e7 100644
--- a/python/mozlint/test/test_formatters.py
+++ b/python/mozlint/test/test_formatters.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import json
 import sys
diff --git a/python/mozlint/test/test_roller.py b/python/mozlint/test/test_roller.py
index b4b82c346c..207b935022 100644
--- a/python/mozlint/test/test_roller.py
+++ b/python/mozlint/test/test_roller.py
@@ -29,7 +29,7 @@ def test_roll_successful(lint, linters, files):
     assert len(result) == 1
     assert lint.return_code == 1
 
-    path = result.keys()[0]
+    path = list(result.keys())[0]
     assert os.path.basename(path) == 'foobar.js'
 
     errors = result[path]
diff --git a/python/mozversioncontrol/mozversioncontrol/__init__.py b/python/mozversioncontrol/mozversioncontrol/__init__.py
index 211d42ef14..e69a9db0bf 100644
--- a/python/mozversioncontrol/mozversioncontrol/__init__.py
+++ b/python/mozversioncontrol/mozversioncontrol/__init__.py
@@ -2,14 +2,33 @@
 # 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, print_function, unicode_literals
 
+from __future__ import print_function
 import os
 import re
 import subprocess
 import which
 
-from distutils.version import LooseVersion
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0
 
 def get_tool_path(tool):
     """Obtain the path of `tool`."""
@@ -30,7 +49,7 @@ def get_tool_path(tool):
                     '|mach bootstrap| to ensure your environment is up to ' +
                     'date.' % tool)
 
-class Repository(object):
+class Repository:
     '''A class wrapping utility methods around version control repositories.'''
     def __init__(self, path, tool):
         self.path = os.path.abspath(path)
@@ -49,7 +68,7 @@ class Repository(object):
         if self._version:
             return self._version
         info = self._run('--version').strip()
-        match = re.search('version ([^\+\)]+)', info)
+        match = re.search(r'version ([^\+\)]+)', info)
         if not match:
             raise Exception('Unable to identify tool version.')
 
@@ -74,7 +93,7 @@ class Repository(object):
 class HgRepository(Repository):
     '''An implementation of `Repository` for Mercurial repositories.'''
     def __init__(self, path):
-        super(HgRepository, self).__init__(path, 'hg')
+        super().__init__(path, 'hg')
         self._env[b'HGPLAIN'] = b'1'
 
     def get_modified_files(self):
@@ -95,11 +114,11 @@ class HgRepository(Repository):
 class GitRepository(Repository):
     '''An implementation of `Repository` for Git repositories.'''
     def __init__(self, path):
-        super(GitRepository, self).__init__(path, 'git')
+        super().__init__(path, 'git')
 
     def get_modified_files(self):
         # This is a little wonky, but it's good enough for this purpose.
-        return [bits[1] for bits in map(lambda line: line.strip().split(), self._run('status', '--porcelain').splitlines()) if 'M' in bits[0]]
+        return [bits[1] for bits in [line.strip().split() for line in self._run('status', '--porcelain').splitlines()] if 'M' in bits[0]]
 
     def add_remove_files(self, path):
         self._run('add', path)
diff --git a/python/mozversioncontrol/mozversioncontrol/repoupdate.py b/python/mozversioncontrol/mozversioncontrol/repoupdate.py
index 08be73a344..291889cfa9 100644
--- a/python/mozversioncontrol/mozversioncontrol/repoupdate.py
+++ b/python/mozversioncontrol/mozversioncontrol/repoupdate.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 import os
 import subprocess
@@ -19,7 +18,7 @@ def update_mercurial_repo(hg, repo, path, revision='default',
         args.extend(global_args)
 
     for host, fingerprint in sorted(hostfingerprints.items()):
-        args.extend(['--config', 'hostfingerprints.%s=%s' % (host,
+        args.extend(['--config', 'hostfingerprints.{}={}'.format(host,
             fingerprint)])
 
     if os.path.exists(path):
diff --git a/python/psutil/docs/conf.py b/python/psutil/docs/conf.py
index ad880110f8..bc906b3948 100644
--- a/python/psutil/docs/conf.py
+++ b/python/psutil/docs/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # psutil documentation build configuration file, created by
 # sphinx-quickstart.
@@ -24,7 +23,7 @@ HERE = os.path.abspath(os.path.dirname(__file__))
 
 def get_version():
     INIT = os.path.abspath(os.path.join(HERE, '../psutil/__init__.py'))
-    with open(INIT, 'r') as f:
+    with open(INIT) as f:
         for line in f:
             if line.startswith('__version__'):
                 ret = eval(line.strip().split(' = ')[1])
@@ -63,7 +62,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = PROJECT_NAME
-copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR)
+copyright = '2009-{}, {}'.format(THIS_YEAR, AUTHOR)
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/python/psutil/examples/disk_usage.py b/python/psutil/examples/disk_usage.py
index d8600a8c47..bf3fa231f6 100755
--- a/python/psutil/examples/disk_usage.py
+++ b/python/psutil/examples/disk_usage.py
@@ -15,6 +15,7 @@ Device               Total     Used     Free  Use %      Type  Mount
 /dev/sda2           600.0M   312.4M   287.6M    52%   fuseblk  /media/Recovery
 """
 
+from __future__ import print_function
 import sys
 import os
 import psutil
@@ -33,14 +34,14 @@ def bytes2human(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = float(n) / prefix[s]
-            return '%.1f%s' % (value, s)
+            return '{:.1f}{}'.format(value, s)
     return "%sB" % n
 
 
 def main():
     templ = "%-17s %8s %8s %8s %5s%% %9s  %s"
-    print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type",
-                   "Mount"))
+    print((templ % ("Device", "Total", "Used", "Free", "Use ", "Type",
+                   "Mount")))
     for part in psutil.disk_partitions(all=False):
         if os.name == 'nt':
             if 'cdrom' in part.opts or part.fstype == '':
@@ -49,14 +50,14 @@ def main():
                 # partition or just hang.
                 continue
         usage = psutil.disk_usage(part.mountpoint)
-        print(templ % (
+        print((templ % (
             part.device,
             bytes2human(usage.total),
             bytes2human(usage.used),
             bytes2human(usage.free),
             int(usage.percent),
             part.fstype,
-            part.mountpoint))
+            part.mountpoint)))
 
 if __name__ == '__main__':
     sys.exit(main())
diff --git a/python/psutil/examples/free.py b/python/psutil/examples/free.py
index 913ca58a4c..1687e5c3e7 100755
--- a/python/psutil/examples/free.py
+++ b/python/psutil/examples/free.py
@@ -13,6 +13,7 @@ Mem:      10125520    8625996    1499524          0     349500    3307836
 Swap:            0          0          0
 """
 
+from __future__ import print_function
 import psutil
 
 
@@ -20,22 +21,22 @@ def main():
     virt = psutil.virtual_memory()
     swap = psutil.swap_memory()
     templ = "%-7s %10s %10s %10s %10s %10s %10s"
-    print(templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache'))
-    print(templ % (
+    print((templ % ('', 'total', 'used', 'free', 'shared', 'buffers', 'cache')))
+    print((templ % (
         'Mem:',
         int(virt.total / 1024),
         int(virt.used / 1024),
         int(virt.free / 1024),
         int(getattr(virt, 'shared', 0) / 1024),
         int(getattr(virt, 'buffers', 0) / 1024),
-        int(getattr(virt, 'cached', 0) / 1024)))
-    print(templ % (
+        int(getattr(virt, 'cached', 0) / 1024))))
+    print((templ % (
         'Swap:', int(swap.total / 1024),
         int(swap.used / 1024),
         int(swap.free / 1024),
         '',
         '',
-        ''))
+        '')))
 
 if __name__ == '__main__':
     main()
diff --git a/python/psutil/examples/ifconfig.py b/python/psutil/examples/ifconfig.py
index e7a436cc0a..8ac04527a2 100644
--- a/python/psutil/examples/ifconfig.py
+++ b/python/psutil/examples/ifconfig.py
@@ -36,7 +36,6 @@ eth0 (speed=100MB, duplex=full, mtu=1500, up=yes):
              broadcast : ff:ff:ff:ff:ff:ff
 """
 
-from __future__ import print_function
 import socket
 
 import psutil
@@ -59,7 +58,7 @@ def main():
     stats = psutil.net_if_stats()
     for nic, addrs in psutil.net_if_addrs().items():
         if nic in stats:
-            print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % (
+            print("{} (speed={}MB, duplex={}, mtu={}, up={}):".format(
                 nic, stats[nic].speed, duplex_map[stats[nic].duplex],
                 stats[nic].mtu, "yes" if stats[nic].isup else "no"))
         else:
diff --git a/python/psutil/examples/iotop.py b/python/psutil/examples/iotop.py
index 16ac7fbf61..d273d45862 100755
--- a/python/psutil/examples/iotop.py
+++ b/python/psutil/examples/iotop.py
@@ -86,7 +86,7 @@ def bytes2human(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = float(n) / prefix[s]
-            return '%.2f %s/s' % (value, s)
+            return '{:.2f} {}/s'.format(value, s)
     return '%.2f B/s' % (n)
 
 
diff --git a/python/psutil/examples/meminfo.py b/python/psutil/examples/meminfo.py
index c463a3de4b..d314a5eea1 100755
--- a/python/psutil/examples/meminfo.py
+++ b/python/psutil/examples/meminfo.py
@@ -30,6 +30,7 @@ Sin        :      0B
 Sout       :      0B
 """
 
+from __future__ import print_function
 import psutil
 
 
@@ -46,7 +47,7 @@ def bytes2human(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = float(n) / prefix[s]
-            return '%.1f%s' % (value, s)
+            return '{:.1f}{}'.format(value, s)
     return "%sB" % n
 
 
@@ -55,7 +56,7 @@ def pprint_ntuple(nt):
         value = getattr(nt, name)
         if name != 'percent':
             value = bytes2human(value)
-        print('%-10s : %7s' % (name.capitalize(), value))
+        print(('%-10s : %7s' % (name.capitalize(), value)))
 
 
 def main():
diff --git a/python/psutil/examples/netstat.py b/python/psutil/examples/netstat.py
index 884622e9e3..af7c224d8e 100755
--- a/python/psutil/examples/netstat.py
+++ b/python/psutil/examples/netstat.py
@@ -19,6 +19,7 @@ tcp   172.17.42.1:55797  127.0.0.1:443    CLOSE_WAIT    13651  GoogleTalkPlugi
 ...
 """
 
+from __future__ import print_function
 import socket
 from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
 
@@ -37,9 +38,9 @@ proto_map = {
 
 def main():
     templ = "%-5s %-30s %-30s %-13s %-6s %s"
-    print(templ % (
+    print((templ % (
         "Proto", "Local address", "Remote address", "Status", "PID",
-        "Program name"))
+        "Program name")))
     proc_names = {}
     for p in psutil.process_iter():
         try:
@@ -51,14 +52,14 @@ def main():
         raddr = ""
         if c.raddr:
             raddr = "%s:%s" % (c.raddr)
-        print(templ % (
+        print((templ % (
             proto_map[(c.family, c.type)],
             laddr,
             raddr or AD,
             c.status,
             c.pid or AD,
             proc_names.get(c.pid, '?')[:15],
-        ))
+        )))
 
 if __name__ == '__main__':
     main()
diff --git a/python/psutil/examples/nettop.py b/python/psutil/examples/nettop.py
index 7a8343ee4c..6b4fc60db2 100755
--- a/python/psutil/examples/nettop.py
+++ b/python/psutil/examples/nettop.py
@@ -87,7 +87,7 @@ def bytes2human(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = float(n) / prefix[s]
-            return '%.2f %s' % (value, s)
+            return '{:.2f} {}'.format(value, s)
     return '%.2f B' % (n)
 
 
diff --git a/python/psutil/examples/pidof.py b/python/psutil/examples/pidof.py
index 8692a3152b..f740c4da43 100755
--- a/python/psutil/examples/pidof.py
+++ b/python/psutil/examples/pidof.py
@@ -47,7 +47,7 @@ def main():
         pgname = sys.argv[1]
     pids = pidof(pgname)
     if pids:
-        print(" ".join(pids))
+        print((" ".join(pids)))
 
 if __name__ == '__main__':
     main()
diff --git a/python/psutil/examples/pmap.py b/python/psutil/examples/pmap.py
index 7593777aef..3525a2859a 100755
--- a/python/psutil/examples/pmap.py
+++ b/python/psutil/examples/pmap.py
@@ -30,6 +30,7 @@ ffffffffff600000         0K  r-xp    [vsyscall]
 ...
 """
 
+from __future__ import print_function
 import sys
 
 import psutil
@@ -39,19 +40,19 @@ def main():
     if len(sys.argv) != 2:
         sys.exit('usage: pmap <pid>')
     p = psutil.Process(int(sys.argv[1]))
-    print("pid=%s, name=%s" % (p.pid, p.name()))
+    print(("pid={}, name={}".format(p.pid, p.name())))
     templ = "%-16s %10s  %-7s %s"
-    print(templ % ("Address", "RSS", "Mode", "Mapping"))
+    print((templ % ("Address", "RSS", "Mode", "Mapping")))
     total_rss = 0
     for m in p.memory_maps(grouped=False):
         total_rss += m.rss
-        print(templ % (
+        print((templ % (
             m.addr.split('-')[0].zfill(16),
             str(m.rss / 1024) + 'K',
             m.perms,
-            m.path))
-    print("-" * 33)
-    print(templ % ("Total", str(total_rss / 1024) + 'K', '', ''))
+            m.path)))
+    print(("-" * 33))
+    print((templ % ("Total", str(total_rss / 1024) + 'K', '', '')))
 
 if __name__ == '__main__':
     main()
diff --git a/python/psutil/examples/process_detail.py b/python/psutil/examples/process_detail.py
index e20371aefe..5f6539e595 100755
--- a/python/psutil/examples/process_detail.py
+++ b/python/psutil/examples/process_detail.py
@@ -49,7 +49,7 @@ def convert_bytes(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = float(n) / prefix[s]
-            return '%.1f%s' % (value, s)
+            return '{:.1f}{}'.format(value, s)
     return "%sB" % n
 
 
@@ -86,7 +86,7 @@ def run(pid):
         started = ACCESS_DENIED
     io = pinfo.get('io_counters', ACCESS_DENIED)
     if pinfo['memory_info'] != ACCESS_DENIED:
-        mem = '%s%% (resident=%s, virtual=%s) ' % (
+        mem = '{}% (resident={}, virtual={}) '.format(
             round(pinfo['memory_percent'], 1),
             convert_bytes(pinfo['memory_info'].rss),
             convert_bytes(pinfo['memory_info'].vms))
@@ -97,7 +97,7 @@ def run(pid):
     print_('pid', pinfo['pid'])
     print_('name', pinfo['name'])
     print_('exe', pinfo['exe'])
-    print_('parent', '%s %s' % (pinfo['ppid'], parent))
+    print_('parent', '{} {}'.format(pinfo['ppid'], parent))
     print_('cmdline', ' '.join(pinfo['cmdline']))
     print_('started', started)
     print_('user', pinfo['username'])
@@ -109,7 +109,7 @@ def run(pid):
         print_('terminal', pinfo['terminal'] or '')
     print_('cwd', pinfo['cwd'])
     print_('memory', mem)
-    print_('cpu', '%s%% (user=%s, system=%s)' % (
+    print_('cpu', '{}% (user={}, system={})'.format(
         pinfo['cpu_percent'],
         getattr(pinfo['cpu_times'], 'user', '?'),
         getattr(pinfo['cpu_times'], 'system', '?')))
@@ -117,23 +117,23 @@ def run(pid):
     print_('niceness', pinfo['nice'])
     print_('num threads', pinfo['num_threads'])
     if io != ACCESS_DENIED:
-        print_('I/O', 'bytes-read=%s, bytes-written=%s' % (
+        print_('I/O', 'bytes-read={}, bytes-written={}'.format(
             convert_bytes(io.read_bytes),
             convert_bytes(io.write_bytes)))
     if children:
         print_('children', '')
         for child in children:
-            print_('', 'pid=%s name=%s' % (child.pid, child.name()))
+            print_('', 'pid={} name={}'.format(child.pid, child.name()))
 
     if pinfo['open_files'] != ACCESS_DENIED:
         print_('open files', '')
         for file in pinfo['open_files']:
-            print_('', 'fd=%s %s ' % (file.fd, file.path))
+            print_('', 'fd={} {} '.format(file.fd, file.path))
 
     if pinfo['threads']:
         print_('running threads', '')
         for thread in pinfo['threads']:
-            print_('', 'id=%s, user-time=%s, sys-time=%s' % (
+            print_('', 'id={}, user-time={}, sys-time={}'.format(
                 thread.id, thread.user_time, thread.system_time))
     if pinfo['connections'] not in (ACCESS_DENIED, []):
         print_('open connections', '')
@@ -149,7 +149,7 @@ def run(pid):
                 rip, rport = '*', '*'
             else:
                 rip, rport = conn.raddr
-            print_('', '%s:%s -> %s:%s type=%s status=%s' % (
+            print_('', '{}:{} -> {}:{} type={} status={}'.format(
                 lip, lport, rip, rport, type, conn.status))
 
 
diff --git a/python/psutil/examples/ps.py b/python/psutil/examples/ps.py
index 2b67bd18ff..5ad82c1d2a 100644
--- a/python/psutil/examples/ps.py
+++ b/python/psutil/examples/ps.py
@@ -11,6 +11,7 @@ $ python examples/ps.py
 ...
 """
 
+from __future__ import print_function
 import datetime
 import os
 import time
@@ -26,8 +27,8 @@ def main():
     if os.name == 'posix':
         attrs.append('uids')
         attrs.append('terminal')
-    print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY",
-                   "START", "TIME", "COMMAND"))
+    print((templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY",
+                   "START", "TIME", "COMMAND")))
     for p in psutil.process_iter():
         try:
             pinfo = p.as_dict(attrs, ad_value='')
@@ -64,7 +65,7 @@ def main():
                 int(pinfo['memory_info'].rss / 1024) or '?'
             memp = pinfo['memory_percent'] and \
                 round(pinfo['memory_percent'], 1) or '?'
-            print(templ % (
+            print((templ % (
                 user[:10],
                 pinfo['pid'],
                 pinfo['cpu_percent'],
@@ -74,7 +75,7 @@ def main():
                 pinfo.get('terminal', '') or '?',
                 ctime,
                 cputime,
-                pinfo['name'].strip() or '?'))
+                pinfo['name'].strip() or '?')))
 
 
 if __name__ == '__main__':
diff --git a/python/psutil/examples/pstree.py b/python/psutil/examples/pstree.py
index 1bf8c9c049..3fd69b4236 100644
--- a/python/psutil/examples/pstree.py
+++ b/python/psutil/examples/pstree.py
@@ -40,7 +40,7 @@ def print_tree(parent, tree, indent=''):
         name = psutil.Process(parent).name()
     except psutil.Error:
         name = "?"
-    print(parent, name)
+    print((parent, name))
     if parent not in tree:
         return
     children = tree[parent][:-1]
diff --git a/python/psutil/examples/top.py b/python/psutil/examples/top.py
index 30df417f55..62aaf37436 100755
--- a/python/psutil/examples/top.py
+++ b/python/psutil/examples/top.py
@@ -92,7 +92,7 @@ def bytes2human(n):
     for s in reversed(symbols):
         if n >= prefix[s]:
             value = int(float(n) / prefix[s])
-            return '%s%s' % (value, s)
+            return '{}{}'.format(value, s)
     return "%sB" % n
 
 
@@ -125,7 +125,7 @@ def print_header(procs_status, num_procs):
     """Print system-related info, above the process list."""
 
     def get_dashes(perc):
-        dashes = "|" * int((float(perc) / 10 * 4))
+        dashes = "|" * int(float(perc) / 10 * 4)
         empty_dashes = " " * (40 - len(dashes))
         return dashes, empty_dashes
 
@@ -161,9 +161,9 @@ def print_header(procs_status, num_procs):
     st = []
     for x, y in procs_status.items():
         if y:
-            st.append("%s=%s" % (x, y))
+            st.append("{}={}".format(x, y))
     st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
-    print_line(" Processes: %s (%s)" % (num_procs, ' '.join(st)))
+    print_line(" Processes: {} ({})".format(num_procs, ' '.join(st)))
     # load average, uptime
     uptime = datetime.utcnow() - datetime.fromtimestamp(psutil.boot_time())
     av1, av2, av3 = os.getloadavg()
@@ -187,8 +187,8 @@ def refresh_window(procs, procs_status):
         # is expressed as: "mm:ss.ms"
         if p.dict['cpu_times'] is not None:
             ctime = timedelta(seconds=sum(p.dict['cpu_times']))
-            ctime = "%s:%s.%s" % (ctime.seconds // 60 % 60,
-                                  str((ctime.seconds % 60)).zfill(2),
+            ctime = "{}:{}.{}".format(ctime.seconds // 60 % 60,
+                                  str(ctime.seconds % 60).zfill(2),
                                   str(ctime.microseconds)[:2])
         else:
             ctime = ''
diff --git a/python/psutil/examples/who.py b/python/psutil/examples/who.py
index b382bebfa3..1d8aa2854e 100755
--- a/python/psutil/examples/who.py
+++ b/python/psutil/examples/who.py
@@ -15,6 +15,7 @@ giampaolo       pts/8           2014-02-24 18:25  (:0)
 giampaolo       pts/9           2014-02-27 01:32  (:0)
 """
 
+from __future__ import print_function
 from datetime import datetime
 
 import psutil
@@ -23,11 +24,11 @@ import psutil
 def main():
     users = psutil.users()
     for user in users:
-        print("%-15s %-15s %s  (%s)" % (
+        print(("%-15s %-15s %s  (%s)" % (
             user.name,
             user.terminal or '-',
             datetime.fromtimestamp(user.started).strftime("%Y-%m-%d %H:%M"),
-            user.host))
+            user.host)))
 
 if __name__ == '__main__':
     main()
diff --git a/python/psutil/psutil/__init__.py b/python/psutil/psutil/__init__.py
index 1444425b8d..b39aa31bac 100644
--- a/python/psutil/psutil/__init__.py
+++ b/python/psutil/psutil/__init__.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
@@ -10,8 +9,8 @@ running processes and system utilization (CPU, memory, disks, network)
 in Python.
 """
 
-from __future__ import division
 
+from __future__ import print_function
 import collections
 import errno
 import functools
@@ -27,7 +26,7 @@ except ImportError:
 
 from . import _common
 from ._common import memoize
-from ._compat import callable, long
+from ._compat import callable, int
 from ._compat import PY3 as _PY3
 
 from ._common import (STATUS_RUNNING,  # NOQA
@@ -194,7 +193,7 @@ class Error(Exception):
         self.msg = msg
 
     def __repr__(self):
-        ret = "%s.%s %s" % (self.__class__.__module__,
+        ret = "{}.{} {}".format(self.__class__.__module__,
                             self.__class__.__name__, self.msg)
         return ret.strip()
 
@@ -213,7 +212,7 @@ class NoSuchProcess(Error):
         self.msg = msg
         if msg is None:
             if name:
-                details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
+                details = "(pid={}, name={})".format(self.pid, repr(self.name))
             else:
                 details = "(pid=%s)" % self.pid
             self.msg = "process no longer exists " + details
@@ -235,10 +234,10 @@ class ZombieProcess(NoSuchProcess):
         self.msg = msg
         if msg is None:
             if name and ppid:
-                details = "(pid=%s, name=%s, ppid=%s)" % (
+                details = "(pid={}, name={}, ppid={})".format(
                     self.pid, repr(self.name), self.ppid)
             elif name:
-                details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
+                details = "(pid={}, name={})".format(self.pid, repr(self.name))
             else:
                 details = "(pid=%s)" % self.pid
             self.msg = "process still exists but it's a zombie " + details
@@ -254,7 +253,7 @@ class AccessDenied(Error):
         self.msg = msg
         if msg is None:
             if (pid is not None) and (name is not None):
-                self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
+                self.msg = "(pid={}, name={})".format(pid, repr(name))
             elif (pid is not None):
                 self.msg = "(pid=%s)" % self.pid
             else:
@@ -272,7 +271,7 @@ class TimeoutExpired(Error):
         self.pid = pid
         self.name = name
         if (pid is not None) and (name is not None):
-            self.msg += " (pid=%s, name=%s)" % (pid, repr(name))
+            self.msg += " (pid={}, name={})".format(pid, repr(name))
         elif (pid is not None):
             self.msg += " (pid=%s)" % self.pid
 
@@ -301,7 +300,7 @@ def _assert_pid_not_reused(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Represents an OS process with the given PID.
     If PID is omitted current process PID (os.getpid()) is used.
     Raise NoSuchProcess if PID does not exist.
@@ -341,7 +340,7 @@ class Process(object):
         if pid is None:
             pid = os.getpid()
         else:
-            if not _PY3 and not isinstance(pid, (int, long)):
+            if not _PY3 and not isinstance(pid, int):
                 raise TypeError('pid must be an integer (got %r)' % pid)
             if pid < 0:
                 raise ValueError('pid must be a positive integer (got %s)'
@@ -395,12 +394,12 @@ class Process(object):
         except AccessDenied:
             details = "(pid=%s)" % (self.pid)
         else:
-            details = "(pid=%s, name=%s)" % (pid, name)
-        return "%s.%s%s" % (self.__class__.__module__,
+            details = "(pid={}, name={})".format(pid, name)
+        return "{}.{}{}".format(self.__class__.__module__,
                             self.__class__.__name__, details)
 
     def __repr__(self):
-        return "<%s at %s>" % (self.__str__(), id(self))
+        return "<{} at {}>".format(self.__str__(), id(self))
 
     def __eq__(self, other):
         # Test for equality with another Process object based
@@ -432,9 +431,9 @@ class Process(object):
         AccessDenied or ZombieProcess exception is raised when
         retrieving that particular process information.
         """
-        excluded_names = set(
-            ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
-             'is_running', 'as_dict', 'parent', 'children', 'rlimit'])
+        excluded_names = {
+            'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
+             'is_running', 'as_dict', 'parent', 'children', 'rlimit'}
         retdict = dict()
         ls = set(attrs or [x for x in dir(self)])
         for name in ls:
@@ -972,7 +971,7 @@ class Process(object):
                 path = tupl[2]
                 nums = tupl[3:]
                 try:
-                    d[path] = map(lambda x, y: x + y, d[path], nums)
+                    d[path] = list(map(lambda x, y: x + y, d[path], nums))
                 except KeyError:
                     d[path] = nums
             nt = _psplatform.pmmap_grouped
@@ -1165,7 +1164,7 @@ class Popen(Process):
     def wait(self, timeout=None):
         if self.__subproc.returncode is not None:
             return self.__subproc.returncode
-        ret = super(Popen, self).wait(timeout)
+        ret = super().wait(timeout)
         self.__subproc.returncode = ret
         return ret
 
@@ -1678,7 +1677,7 @@ def disk_io_counters(perdisk=False):
             rawdict[disk] = _common.sdiskio(*fields)
         return rawdict
     else:
-        return _common.sdiskio(*[sum(x) for x in zip(*rawdict.values())])
+        return _common.sdiskio(*[sum(x) for x in zip(*list(rawdict.values()))])
 
 
 # =====================================================================
@@ -1713,7 +1712,7 @@ def net_io_counters(pernic=False):
             rawdict[nic] = _common.snetio(*fields)
         return rawdict
     else:
-        return _common.snetio(*[sum(x) for x in zip(*rawdict.values())])
+        return _common.snetio(*[sum(x) for x in zip(*list(rawdict.values()))])
 
 
 def net_connections(kind='inet'):
@@ -1836,8 +1835,8 @@ def test():
     if _POSIX:
         attrs.append('uids')
         attrs.append('terminal')
-    print(templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY",
-                   "START", "TIME", "COMMAND"))
+    print((templ % ("USER", "PID", "%CPU", "%MEM", "VSZ", "RSS", "TTY",
+                   "START", "TIME", "COMMAND")))
     for p in process_iter():
         try:
             pinfo = p.as_dict(attrs, ad_value='')
@@ -1866,7 +1865,7 @@ def test():
                 int(pinfo['memory_info'].rss / 1024) or '?'
             memp = pinfo['memory_percent'] and \
                 round(pinfo['memory_percent'], 1) or '?'
-            print(templ % (
+            print((templ % (
                 user[:10],
                 pinfo['pid'],
                 pinfo['cpu_percent'],
@@ -1876,12 +1875,9 @@ def test():
                 pinfo.get('terminal', '') or '?',
                 ctime,
                 cputime,
-                pinfo['name'].strip() or '?'))
+                pinfo['name'].strip() or '?')))
 
 
 del memoize, division
-if sys.version_info < (3, 0):
-    del num
-
 if __name__ == "__main__":
     test()
diff --git a/python/psutil/psutil/_common.py b/python/psutil/psutil/_common.py
index e9acf595d7..b338a0ba27 100644
--- a/python/psutil/psutil/_common.py
+++ b/python/psutil/psutil/_common.py
@@ -6,7 +6,6 @@
 
 """Common objects shared by all _ps* modules."""
 
-from __future__ import division
 import errno
 import functools
 import os
diff --git a/python/psutil/psutil/_compat.py b/python/psutil/psutil/_compat.py
index 38744a84ae..f7326834ce 100644
--- a/python/psutil/psutil/_compat.py
+++ b/python/psutil/psutil/_compat.py
@@ -17,17 +17,17 @@ PY3 = sys.version_info[0] == 3
 if PY3:
     long = int
     xrange = range
-    unicode = str
+    str = str
 
     def u(s):
         return s
 else:
-    long = long
+    long = int
     xrange = xrange
-    unicode = unicode
+    str = str
 
     def u(s):
-        return unicode(s, "unicode_escape")
+        return str(s, "unicode_escape")
 
 
 # removed in 3.0, reintroduced in 3.2
@@ -67,7 +67,7 @@ except ImportError:
 
     def _make_key(args, kwds, typed,
                   kwd_mark=(object(), ),
-                  fasttypes=set((int, str, frozenset, type(None))),
+                  fasttypes={int, str, frozenset, type(None)},
                   sorted=sorted, tuple=tuple, type=type, len=len):
         key = args
         if kwds:
diff --git a/python/psutil/psutil/_psbsd.py b/python/psutil/psutil/_psbsd.py
index db54a02e13..f2d3a4c6b7 100644
--- a/python/psutil/psutil/_psbsd.py
+++ b/python/psutil/psutil/_psbsd.py
@@ -84,7 +84,7 @@ def virtual_memory():
 
 def swap_memory():
     """System swap memory as (total, used, free, sin, sout) namedtuple."""
-    total, used, free, sin, sout = [x * PAGESIZE for x in cext.swap_mem()]
+    total, used, free, sin, sout = (x * PAGESIZE for x in cext.swap_mem())
     percent = usage_percent(used, total, _round=1)
     return _common.sswap(total, used, free, percent, sin, sout)
 
@@ -216,7 +216,7 @@ def net_connections(kind):
 
 def net_if_stats():
     """Get NIC stats (isup, duplex, speed, mtu)."""
-    names = net_io_counters().keys()
+    names = list(net_io_counters().keys())
     ret = {}
     for name in names:
         isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
@@ -258,7 +258,7 @@ def wrap_exceptions(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Wrapper class around underlying C implementation."""
 
     __slots__ = ["pid", "_name", "_ppid"]
diff --git a/python/psutil/psutil/_pslinux.py b/python/psutil/psutil/_pslinux.py
index 7eb25f519c..f956ef44db 100644
--- a/python/psutil/psutil/_pslinux.py
+++ b/python/psutil/psutil/_pslinux.py
@@ -6,7 +6,6 @@
 
 """Linux platform implementation."""
 
-from __future__ import division
 
 import base64
 import errno
@@ -25,7 +24,8 @@ from . import _psutil_linux as cext
 from . import _psutil_posix as cext_posix
 from ._common import isfile_strict, usage_percent
 from ._common import NIC_DUPLEX_FULL, NIC_DUPLEX_HALF, NIC_DUPLEX_UNKNOWN
-from ._compat import PY3, long
+from ._compat import PY3, int
+import six
 
 if sys.version_info >= (3, 4):
     import enum
@@ -262,8 +262,8 @@ def cpu_count_logical():
         # https://github.com/giampaolo/psutil/issues/200
         # try to parse /proc/stat as a last resort
         if num == 0:
-            search = re.compile('cpu\d')
-            with open('/proc/stat', 'rt') as f:
+            search = re.compile(r'cpu\d')
+            with open('/proc/stat') as f:
                 for line in f:
                     line = line.split(' ')[0]
                     if search.match(line):
@@ -382,7 +382,7 @@ class Connections:
         inodes = defaultdict(list)
         for fd in os.listdir("/proc/%s/fd" % pid):
             try:
-                inode = os.readlink("/proc/%s/fd/%s" % (pid, fd))
+                inode = os.readlink("/proc/{}/fd/{}".format(pid, fd))
             except OSError as err:
                 # ENOENT == file which is gone in the meantime;
                 # os.stat('/proc/%s' % self.pid) will be done later
@@ -471,7 +471,7 @@ class Connections:
         if file.endswith('6') and not os.path.exists(file):
             # IPv6 not supported
             return
-        with open(file, 'rt') as f:
+        with open(file) as f:
             f.readline()  # skip the first line
             for line in f:
                 try:
@@ -479,7 +479,7 @@ class Connections:
                         line.split()[:10]
                 except ValueError:
                     raise RuntimeError(
-                        "error while parsing %s; malformed line %r" % (
+                        "error while parsing {}; malformed line {!r}".format(
                             file, line))
                 if inode in inodes:
                     # # We assume inet sockets are unique, so we error
@@ -504,7 +504,7 @@ class Connections:
 
     def process_unix(self, file, family, inodes, filter_pid=None):
         """Parse /proc/net/unix files."""
-        with open(file, 'rt') as f:
+        with open(file) as f:
             f.readline()  # skip the first line
             for line in f:
                 tokens = line.split()
@@ -512,7 +512,7 @@ class Connections:
                     _, _, _, _, type_, _, inode = tokens[0:7]
                 except ValueError:
                     raise RuntimeError(
-                        "error while parsing %s; malformed line %r" % (
+                        "error while parsing {}; malformed line {!r}".format(
                             file, line))
                 if inode in inodes:
                     # With UNIX sockets we can have a single inode
@@ -575,7 +575,7 @@ def net_io_counters():
     """Return network I/O statistics for every network interface
     installed on the system as a dict of raw tuples.
     """
-    with open("/proc/net/dev", "rt") as f:
+    with open("/proc/net/dev") as f:
         lines = f.readlines()
     retdict = {}
     for line in lines[2:]:
@@ -601,7 +601,7 @@ def net_if_stats():
     duplex_map = {cext.DUPLEX_FULL: NIC_DUPLEX_FULL,
                   cext.DUPLEX_HALF: NIC_DUPLEX_HALF,
                   cext.DUPLEX_UNKNOWN: NIC_DUPLEX_UNKNOWN}
-    names = net_io_counters().keys()
+    names = list(net_io_counters().keys())
     ret = {}
     for name in names:
         isup, duplex, speed, mtu = cext.net_if_stats(name)
@@ -626,7 +626,7 @@ def disk_io_counters():
 
     # determine partitions we want to look for
     partitions = []
-    with open("/proc/partitions", "rt") as f:
+    with open("/proc/partitions") as f:
         lines = f.readlines()[2:]
     for line in reversed(lines):
         _, _, _, name = line.split()
@@ -643,7 +643,7 @@ def disk_io_counters():
                 partitions.append(name)
     #
     retdict = {}
-    with open("/proc/diskstats", "rt") as f:
+    with open("/proc/diskstats") as f:
         lines = f.readlines()
     for line in lines:
         # http://www.mjmwired.net/kernel/Documentation/iostats.txt
@@ -669,7 +669,7 @@ def disk_io_counters():
 def disk_partitions(all=False):
     """Return mounted disk partitions as a list of namedtuples"""
     fstypes = set()
-    with open("/proc/filesystems", "r") as f:
+    with open("/proc/filesystems") as f:
         for line in f:
             line = line.strip()
             if not line.startswith("nodev"):
@@ -707,7 +707,7 @@ def wrap_exceptions(fun):
     def wrapper(self, *args, **kwargs):
         try:
             return fun(self, *args, **kwargs)
-        except EnvironmentError as err:
+        except OSError as err:
             # support for private module import
             if NoSuchProcess is None or AccessDenied is None:
                 raise
@@ -736,7 +736,7 @@ def wrap_exceptions_w_zombie(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Linux process implementation."""
 
     __slots__ = ["pid", "_name", "_ppid"]
@@ -887,7 +887,7 @@ class Process(object):
         #  ============================================================
         with open("/proc/%s/statm" % self.pid, "rb") as f:
             vms, rss, shared, text, lib, data, dirty = \
-                [int(x) * PAGESIZE for x in f.readline().split()[:7]]
+                (int(x) * PAGESIZE for x in f.readline().split()[:7])
         return pextmem(rss, vms, shared, text, lib, data, dirty)
 
     if os.path.exists('/proc/%s/smaps' % os.getpid()):
@@ -898,7 +898,7 @@ class Process(object):
             Fields are explained in 'man proc'; here is an updated (Apr 2012)
             version: http://goo.gl/fmebo
             """
-            with open("/proc/%s/smaps" % self.pid, "rt") as f:
+            with open("/proc/%s/smaps" % self.pid) as f:
                 first_line = f.readline()
                 current_block = [first_line]
 
@@ -996,11 +996,11 @@ class Process(object):
         retlist = []
         hit_enoent = False
         for thread_id in thread_ids:
-            fname = "/proc/%s/task/%s/stat" % (self.pid, thread_id)
+            fname = "/proc/{}/task/{}/stat".format(self.pid, thread_id)
             try:
                 with open(fname, 'rb') as f:
                     st = f.read().strip()
-            except IOError as err:
+            except OSError as err:
                 if err.errno == errno.ENOENT:
                     # no such file or directory; it means thread
                     # disappeared on us
@@ -1062,7 +1062,7 @@ class Process(object):
         @wrap_exceptions
         def ionice_set(self, ioclass, value):
             if value is not None:
-                if not PY3 and not isinstance(value, (int, long)):
+                if not PY3 and not isinstance(value, int):
                     msg = "value argument is not an integer (gor %r)" % value
                     raise TypeError(msg)
                 if not 0 <= value <= 8:
@@ -1138,7 +1138,7 @@ class Process(object):
         files = os.listdir("/proc/%s/fd" % self.pid)
         hit_enoent = False
         for fd in files:
-            file = "/proc/%s/fd/%s" % (self.pid, fd)
+            file = "/proc/{}/fd/{}".format(self.pid, fd)
             try:
                 file = os.readlink(file)
             except OSError as err:
diff --git a/python/psutil/psutil/_psosx.py b/python/psutil/psutil/_psosx.py
index 41875fe404..ef8b8f823e 100644
--- a/python/psutil/psutil/_psosx.py
+++ b/python/psutil/psutil/_psosx.py
@@ -170,7 +170,7 @@ def net_connections(kind='inet'):
 
 def net_if_stats():
     """Get NIC stats (isup, duplex, speed, mtu)."""
-    names = net_io_counters().keys()
+    names = list(net_io_counters().keys())
     ret = {}
     for name in names:
         isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
@@ -212,7 +212,7 @@ def wrap_exceptions(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Wrapper class around underlying C implementation."""
 
     __slots__ = ["pid", "_name", "_ppid"]
diff --git a/python/psutil/psutil/_psposix.py b/python/psutil/psutil/_psposix.py
index 5bb16a386d..69bcf63595 100644
--- a/python/psutil/psutil/_psposix.py
+++ b/python/psutil/psutil/_psposix.py
@@ -13,7 +13,7 @@ import sys
 import time
 
 from ._common import sdiskusage, usage_percent, memoize
-from ._compat import PY3, unicode
+from ._compat import PY3, str
 
 
 class TimeoutExpired(Exception):
@@ -120,7 +120,7 @@ def disk_usage(path):
     try:
         st = os.statvfs(path)
     except UnicodeEncodeError:
-        if not PY3 and isinstance(path, unicode):
+        if not PY3 and isinstance(path, str):
             # this is a bug with os.statvfs() and unicode on
             # Python 2, see:
             # - https://github.com/giampaolo/psutil/issues/416
diff --git a/python/psutil/psutil/_pssunos.py b/python/psutil/psutil/_pssunos.py
index bc35a718c3..046ede4ca3 100644
--- a/python/psutil/psutil/_pssunos.py
+++ b/python/psutil/psutil/_pssunos.py
@@ -252,7 +252,7 @@ def wrap_exceptions(fun):
     def wrapper(self, *args, **kwargs):
         try:
             return fun(self, *args, **kwargs)
-        except EnvironmentError as err:
+        except OSError as err:
             # support for private module import
             if (NoSuchProcess is None or AccessDenied is None or
                     ZombieProcess is None):
@@ -271,7 +271,7 @@ def wrap_exceptions(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Wrapper class around underlying C implementation."""
 
     __slots__ = ["pid", "_name", "_ppid"]
@@ -317,7 +317,7 @@ class Process(object):
         # fine.
         try:
             return cext_posix.getpriority(self.pid)
-        except EnvironmentError as err:
+        except OSError as err:
             # 48 is 'operation not supported' but errno does not expose
             # it. It occurs for low system pids.
             if err.errno in (errno.ENOENT, errno.ESRCH, 48):
@@ -411,7 +411,7 @@ class Process(object):
             try:
                 utime, stime = cext.query_process_thread(
                     self.pid, tid)
-            except EnvironmentError as err:
+            except OSError as err:
                 # ENOENT == thread gone in meantime
                 if err.errno == errno.ENOENT:
                     hit_enoent = True
@@ -458,14 +458,14 @@ class Process(object):
                              stderr=subprocess.PIPE)
         stdout, stderr = p.communicate()
         if PY3:
-            stdout, stderr = [x.decode(sys.stdout.encoding)
-                              for x in (stdout, stderr)]
+            stdout, stderr = (x.decode(sys.stdout.encoding)
+                              for x in (stdout, stderr))
         if p.returncode != 0:
             if 'permission denied' in stderr.lower():
                 raise AccessDenied(self.pid, self._name)
             if 'no such process' in stderr.lower():
                 raise NoSuchProcess(self.pid, self._name)
-            raise RuntimeError("%r command error\n%s" % (cmd, stderr))
+            raise RuntimeError("{!r} command error\n{}".format(cmd, stderr))
 
         lines = stdout.split('\n')[2:]
         for i, line in enumerate(lines):
@@ -504,7 +504,7 @@ class Process(object):
     @wrap_exceptions
     def memory_maps(self):
         def toaddr(start, end):
-            return '%s-%s' % (hex(start)[2:].strip('L'),
+            return '{}-{}'.format(hex(start)[2:].strip('L'),
                               hex(end)[2:].strip('L'))
 
         retlist = []
@@ -515,7 +515,7 @@ class Process(object):
             addr = toaddr(addr, addrsize)
             if not name.startswith('['):
                 try:
-                    name = os.readlink('/proc/%s/path/%s' % (self.pid, name))
+                    name = os.readlink('/proc/{}/path/{}'.format(self.pid, name))
                 except OSError as err:
                     if err.errno == errno.ENOENT:
                         # sometimes the link may not be resolved by
@@ -524,7 +524,7 @@ class Process(object):
                         # unresolved link path.
                         # This seems an incosistency with /proc similar
                         # to: http://goo.gl/55XgO
-                        name = '/proc/%s/path/%s' % (self.pid, name)
+                        name = '/proc/{}/path/{}'.format(self.pid, name)
                         hit_enoent = True
                     else:
                         raise
diff --git a/python/psutil/psutil/_pswindows.py b/python/psutil/psutil/_pswindows.py
index 2d8babb19c..c609d24441 100644
--- a/python/psutil/psutil/_pswindows.py
+++ b/python/psutil/psutil/_pswindows.py
@@ -16,7 +16,7 @@ from . import _common
 from . import _psutil_windows as cext
 from ._common import conn_tmap, usage_percent, isfile_strict
 from ._common import sockfam_to_enum, socktype_to_enum
-from ._compat import PY3, xrange, lru_cache, long
+from ._compat import PY3, xrange, lru_cache, int
 from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS,
                               BELOW_NORMAL_PRIORITY_CLASS,
                               HIGH_PRIORITY_CLASS,
@@ -143,7 +143,7 @@ def disk_usage(path):
     """Return disk usage associated with path."""
     try:
         total, free = cext.disk_usage(path)
-    except WindowsError:
+    except OSError:
         if not os.path.exists(path):
             msg = "No such file or directory: '%s'" % path
             raise OSError(errno.ENOENT, msg)
@@ -262,7 +262,7 @@ def wrap_exceptions(fun):
     return wrapper
 
 
-class Process(object):
+class Process:
     """Wrapper class around underlying C implementation."""
 
     __slots__ = ["pid", "_name", "_ppid"]
@@ -503,7 +503,7 @@ class Process(object):
     @wrap_exceptions
     def cpu_affinity_get(self):
         def from_bitmask(x):
-            return [i for i in xrange(64) if (1 << i) & x]
+            return [i for i in range(64) if (1 << i) & x]
         bitmask = cext.proc_cpu_affinity_get(self.pid)
         return from_bitmask(bitmask)
 
@@ -523,7 +523,7 @@ class Process(object):
         allcpus = list(range(len(per_cpu_times())))
         for cpu in value:
             if cpu not in allcpus:
-                if not isinstance(cpu, (int, long)):
+                if not isinstance(cpu, int):
                     raise TypeError(
                         "invalid CPU %r; an integer is required" % cpu)
                 else:
diff --git a/python/psutil/setup.py b/python/psutil/setup.py
index 4c42548ef3..1643f48cac 100644
--- a/python/psutil/setup.py
+++ b/python/psutil/setup.py
@@ -22,7 +22,7 @@ HERE = os.path.abspath(os.path.dirname(__file__))
 
 def get_version():
     INIT = os.path.join(HERE, 'psutil/__init__.py')
-    with open(INIT, 'r') as f:
+    with open(INIT) as f:
         for line in f:
             if line.startswith('__version__'):
                 ret = eval(line.strip().split(' = ')[1])
@@ -36,7 +36,7 @@ def get_version():
 
 def get_description():
     README = os.path.join(HERE, 'README.rst')
-    with open(README, 'r') as f:
+    with open(README) as f:
         return f.read()
 
 
diff --git a/python/psutil/test/_bsd.py b/python/psutil/test/_bsd.py
index e4a3225d20..51cf8accd3 100644
--- a/python/psutil/test/_bsd.py
+++ b/python/psutil/test/_bsd.py
@@ -103,9 +103,9 @@ class BSDSpecificTestCase(unittest.TestCase):
             self.assertEqual(usage.total, total)
             # 10 MB tollerance
             if abs(usage.free - free) > 10 * 1024 * 1024:
-                self.fail("psutil=%s, df=%s" % (usage.free, free))
+                self.fail("psutil={}, df={}".format(usage.free, free))
             if abs(usage.used - used) > 10 * 1024 * 1024:
-                self.fail("psutil=%s, df=%s" % (usage.used, used))
+                self.fail("psutil={}, df={}".format(usage.used, used))
 
     @retry_before_failing()
     def test_memory_maps(self):
@@ -117,7 +117,7 @@ class BSDSpecificTestCase(unittest.TestCase):
             fields = line.split()
             _, start, stop, perms, res = fields[:5]
             map = maps.pop()
-            self.assertEqual("%s-%s" % (start, stop), map.addr)
+            self.assertEqual("{}-{}".format(start, stop), map.addr)
             self.assertEqual(int(res), map.rss)
             if not map.path.startswith('['):
                 self.assertEqual(fields[10], map.path)
@@ -243,7 +243,7 @@ class BSDSpecificTestCase(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(BSDSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(BSDSpecificTestCase))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/_linux.py b/python/psutil/test/_linux.py
index c1927ea8b2..d82313255a 100644
--- a/python/psutil/test/_linux.py
+++ b/python/psutil/test/_linux.py
@@ -6,7 +6,6 @@
 
 """Linux specific tests.  These are implicitly run by test_psutil.py."""
 
-from __future__ import division
 import contextlib
 import errno
 import fcntl
@@ -24,7 +23,7 @@ import warnings
 try:
     from unittest import mock  # py3
 except ImportError:
-    import mock  # requires "pip install mock"
+    from unittest import mock
 
 from test_psutil import POSIX, TOLERANCE, TRAVIS, LINUX
 from test_psutil import (skip_on_not_implemented, sh, get_test_subprocess,
@@ -65,8 +64,8 @@ def get_mac_address(ifname):
             def ord(x):
                 return x
         else:
-            import __builtin__
-            ord = __builtin__.ord
+            import builtins
+            ord = builtins.ord
         return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
 
 
@@ -98,9 +97,9 @@ class LinuxSpecificTestCase(unittest.TestCase):
             self.assertEqual(usage.total, total)
             # 10 MB tollerance
             if abs(usage.free - free) > 10 * 1024 * 1024:
-                self.fail("psutil=%s, df=%s" % (usage.free, free))
+                self.fail("psutil={}, df={}".format(usage.free, free))
             if abs(usage.used - used) > 10 * 1024 * 1024:
-                self.fail("psutil=%s, df=%s" % (usage.used, used))
+                self.fail("psutil={}, df={}".format(usage.used, used))
 
     def test_memory_maps(self):
         sproc = get_test_subprocess()
@@ -176,7 +175,7 @@ class LinuxSpecificTestCase(unittest.TestCase):
     @unittest.skipIf(TRAVIS, "unknown failure on travis")
     def test_cpu_times(self):
         fields = psutil.cpu_times()._fields
-        kernel_ver = re.findall('\d+\.\d+\.\d+', os.uname()[2])[0]
+        kernel_ver = re.findall(r'\d+\.\d+\.\d+', os.uname()[2])[0]
         kernel_ver_info = tuple(map(int, kernel_ver.split('.')))
         if kernel_ver_info >= (2, 6, 11):
             self.assertIn('steal', fields)
@@ -208,11 +207,11 @@ class LinuxSpecificTestCase(unittest.TestCase):
         found = 0
         for line in out.split('\n'):
             line = line.strip()
-            if re.search("^\d+:", line):
+            if re.search(r"^\d+:", line):
                 found += 1
                 name = line.split(':')[1].strip()
-                self.assertIn(name, nics.keys())
-        self.assertEqual(len(nics), found, msg="%s\n---\n%s" % (
+                self.assertIn(name, list(nics.keys()))
+        self.assertEqual(len(nics), found, msg="{}\n---\n{}".format(
             pprint.pformat(nics), out))
 
     @unittest.skipUnless(which("nproc"), "nproc utility not available")
@@ -404,7 +403,7 @@ class LinuxSpecificTestCase(unittest.TestCase):
 
     def test_disk_partitions_mocked(self):
         # Test that ZFS partitions are returned.
-        with open("/proc/filesystems", "r") as f:
+        with open("/proc/filesystems") as f:
             data = f.read()
         if 'zfs' in data:
             for part in psutil.disk_partitions():
@@ -464,7 +463,7 @@ class LinuxSpecificTestCase(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(LinuxSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(LinuxSpecificTestCase))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/_osx.py b/python/psutil/test/_osx.py
index 6e6e4380ef..30fafea7bb 100644
--- a/python/psutil/test/_osx.py
+++ b/python/psutil/test/_osx.py
@@ -44,7 +44,7 @@ def vm_stat(field):
             break
     else:
         raise ValueError("line not found")
-    return int(re.search('\d+', line).group(0)) * PAGESIZE
+    return int(re.search(r'\d+', line).group(0)) * PAGESIZE
 
 
 @unittest.skipUnless(OSX, "not an OSX system")
@@ -151,7 +151,7 @@ class OSXSpecificTestCase(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(OSXSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(OSXSpecificTestCase))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/_posix.py b/python/psutil/test/_posix.py
index e6c56aac3e..be9f0d6497 100644
--- a/python/psutil/test/_posix.py
+++ b/python/psutil/test/_posix.py
@@ -192,7 +192,7 @@ class PosixSpecificTestCase(unittest.TestCase):
                     break
             else:
                 self.fail(
-                    "couldn't find %s nic in 'ifconfig -a' output\n%s" % (
+                    "couldn't find {} nic in 'ifconfig -a' output\n{}".format(
                         nic, output))
 
     @retry_before_failing()
@@ -249,7 +249,7 @@ class PosixSpecificTestCase(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(PosixSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(PosixSpecificTestCase))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/_sunos.py b/python/psutil/test/_sunos.py
index 3d54ccd8cf..3f99f01ab5 100644
--- a/python/psutil/test/_sunos.py
+++ b/python/psutil/test/_sunos.py
@@ -39,7 +39,7 @@ class SunOSSpecificTestCase(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(SunOSSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(SunOSSpecificTestCase))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/_windows.py b/python/psutil/test/_windows.py
index b7477bfeb4..eab325f6fa 100644
--- a/python/psutil/test/_windows.py
+++ b/python/psutil/test/_windows.py
@@ -18,7 +18,7 @@ import traceback
 from test_psutil import APPVEYOR, WINDOWS
 from test_psutil import get_test_subprocess, reap_children, unittest
 
-import mock
+from unittest import mock
 try:
     import wmi
 except ImportError:
@@ -29,7 +29,7 @@ try:
 except ImportError:
     win32api = win32con = None
 
-from psutil._compat import PY3, callable, long
+from psutil._compat import PY3, callable, int
 import psutil
 
 
@@ -91,7 +91,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
         out = p.communicate()[0]
         if PY3:
             out = str(out, sys.stdout.encoding)
-        nics = psutil.net_io_counters(pernic=True).keys()
+        nics = list(psutil.net_io_counters(pernic=True).keys())
         for nic in nics:
             if "pseudo-interface" in nic.replace(' ', '-').lower():
                 continue
@@ -134,7 +134,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
         w = wmi.WMI().Win32_Process(ProcessId=self.pid)[0]
         p = psutil.Process(self.pid)
         domain, _, username = w.GetOwner()
-        username = "%s\\%s" % (domain, username)
+        username = "{}\\{}".format(domain, username)
         self.assertEqual(p.username(), username)
 
     @unittest.skipIf(wmi is None, "wmi module is not installed")
@@ -157,7 +157,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
         # returned instead.
         wmi_usage = int(w.PageFileUsage)
         if (vms != wmi_usage) and (vms != wmi_usage * 1024):
-            self.fail("wmi=%s, psutil=%s" % (wmi_usage, vms))
+            self.fail("wmi={}, psutil={}".format(wmi_usage, vms))
 
     @unittest.skipIf(wmi is None, "wmi module is not installed")
     def test_process_create_time(self):
@@ -201,7 +201,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
         # Note: this test might fail if the OS is starting/killing
         # other processes in the meantime
         w = wmi.WMI().Win32_Process()
-        wmi_pids = set([x.ProcessId for x in w])
+        wmi_pids = {x.ProcessId for x in w}
         psutil_pids = set(psutil.pids())
         self.assertEqual(wmi_pids, psutil_pids)
 
@@ -228,7 +228,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
                     self.assertEqual(usage.free, wmi_free)
                     # 10 MB tollerance
                     if abs(usage.free - wmi_free) > 10 * 1024 * 1024:
-                        self.fail("psutil=%s, wmi=%s" % (
+                        self.fail("psutil={}, wmi={}".format(
                             usage.free, wmi_free))
                     break
             else:
@@ -282,8 +282,7 @@ class WindowsSpecificTestCase(unittest.TestCase):
             self.fail('\n' + '\n'.join(failures))
 
     def test_name_always_available(self):
-        # On Windows name() is never supposed to raise AccessDenied,
-        # see https://github.com/giampaolo/psutil/issues/627
+        # On Windows name() is never supposed to raise AccessDenied(# see https://github.com/giampaolo/psutil/issues/627)
         for p in psutil.process_iter():
             try:
                 p.name()
@@ -317,7 +316,7 @@ class TestDualProcessImplementation(unittest.TestCase):
             if isinstance(obj, tuple):
                 for value in obj:
                     self.assertGreaterEqual(value, 0, msg=obj)
-            elif isinstance(obj, (int, long, float)):
+            elif isinstance(obj, (int, int, float)):
                 self.assertGreaterEqual(obj, 0)
             else:
                 assert 0  # case not handled which needs to be fixed
@@ -326,7 +325,7 @@ class TestDualProcessImplementation(unittest.TestCase):
             if ret1 == ret2:
                 return
             else:
-                if isinstance(ret2, (int, long, float)):
+                if isinstance(ret2, (int, int, float)):
                     diff = abs(ret1 - ret2)
                     self.assertLessEqual(diff, tolerance)
                 elif isinstance(ret2, tuple):
@@ -376,7 +375,7 @@ class TestDualProcessImplementation(unittest.TestCase):
                         compare_with_tolerance(ret, rawtupl, tolerance)
                 except AssertionError:
                     trace = traceback.format_exc()
-                    msg = '%s\npid=%s, method=%r, ret_1=%r, ret_2=%r' % (
+                    msg = '{}\npid={}, method={!r}, ret_1={!r}, ret_2={!r}'.format(
                         trace, p.pid, name, ret, nt)
                     failures.append(msg)
                     break
@@ -454,8 +453,8 @@ class TestDualProcessImplementation(unittest.TestCase):
 
 def main():
     test_suite = unittest.TestSuite()
-    test_suite.addTest(unittest.makeSuite(WindowsSpecificTestCase))
-    test_suite.addTest(unittest.makeSuite(TestDualProcessImplementation))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(WindowsSpecificTestCase))
+    test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(TestDualProcessImplementation))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/test_memory_leaks.py b/python/psutil/test/test_memory_leaks.py
index 6f02dc0acf..879d3c5748 100644
--- a/python/psutil/test/test_memory_leaks.py
+++ b/python/psutil/test/test_memory_leaks.py
@@ -48,7 +48,7 @@ class Base(unittest.TestCase):
 
     def execute(self, function, *args, **kwargs):
         def call_many_times():
-            for x in xrange(LOOPS - 1):
+            for x in range(LOOPS - 1):
                 self.call(function, *args, **kwargs)
             del x
             gc.collect()
@@ -436,7 +436,7 @@ def main():
              TestProcessObjectLeaks,
              TestModuleFunctionsLeaks]
     for test in tests:
-        test_suite.addTest(unittest.makeSuite(test))
+        test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(test))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/psutil/test/test_psutil.py b/python/psutil/test/test_psutil.py
index 3b2e3587ae..da180081f8 100644
--- a/python/psutil/test/test_psutil.py
+++ b/python/psutil/test/test_psutil.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
@@ -13,7 +12,6 @@ If you're on Python < 2.7 unittest2 module must be installed first:
 https://pypi.python.org/pypi/unittest2
 """
 
-from __future__ import division
 
 import ast
 import atexit
@@ -50,10 +48,10 @@ except ImportError:
 try:
     from unittest import mock  # py3
 except ImportError:
-    import mock  # requires "pip install mock"
+    from unittest import mock
 
 import psutil
-from psutil._compat import PY3, callable, long, unicode
+from psutil._compat import PY3, callable, int, str
 
 if sys.version_info < (2, 7):
     import unittest2 as unittest  # https://pypi.python.org/pypi/unittest2
@@ -85,7 +83,7 @@ TESTFN_UNICODE = TESTFN + "ƒőő"
 TESTFILE_PREFIX = 'psutil-test-suite-'
 if not PY3:
     try:
-        TESTFN_UNICODE = unicode(TESTFN_UNICODE, sys.getfilesystemencoding())
+        TESTFN_UNICODE = str(TESTFN_UNICODE, sys.getfilesystemencoding())
     except UnicodeDecodeError:
         TESTFN_UNICODE = TESTFN + "???"
 
@@ -273,14 +271,14 @@ def wait_for_file(fname, timeout=GLOBAL_TIMEOUT, delete_file=True):
     stop_at = time.time() + 3
     while time.time() < stop_at:
         try:
-            with open(fname, "r") as f:
+            with open(fname) as f:
                 data = f.read()
             if not data:
                 continue
             if delete_file:
                 os.remove(fname)
             return data
-        except IOError:
+        except OSError:
             time.sleep(0.001)
     raise RuntimeError("timed out (couldn't read file)")
 
@@ -325,16 +323,16 @@ def check_ip_address(addr, family):
             assert 0 <= num <= 255, addr
         if ipaddress:
             if not PY3:
-                addr = unicode(addr)
+                addr = str(addr)
             ipaddress.IPv4Address(addr)
     elif family == AF_INET6:
         assert isinstance(addr, str), addr
         if ipaddress:
             if not PY3:
-                addr = unicode(addr)
+                addr = str(addr)
             ipaddress.IPv6Address(addr)
     elif family == psutil.AF_LINK:
-        assert re.match('([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr
+        assert re.match(r'([a-fA-F0-9]{2}[:|\-]?){6}', addr) is not None, addr
     else:
         raise ValueError("unknown family %r", family)
 
@@ -378,7 +376,7 @@ def check_connection_ntuple(conn):
             with contextlib.closing(s):
                 try:
                     s.bind((conn.laddr[0], 0))
-                except socket.error as err:
+                except OSError as err:
                     if err.errno != errno.EADDRNOTAVAIL:
                         raise
     elif conn.family == AF_UNIX:
@@ -390,7 +388,7 @@ def check_connection_ntuple(conn):
         if hasattr(socket, 'fromfd') and not WINDOWS:
             try:
                 dupsock = socket.fromfd(conn.fd, conn.family, conn.type)
-            except (socket.error, OSError) as err:
+            except OSError as err:
                 if err.args[0] != errno.EBADF:
                     raise
             else:
@@ -494,7 +492,7 @@ def supports_ipv6():
     try:
         sock = socket.socket(AF_INET6, SOCK_STREAM)
         sock.bind(("::1", 0))
-    except (socket.error, socket.gaierror):
+    except (OSError, socket.gaierror):
         return False
     else:
         return True
@@ -509,7 +507,7 @@ if WINDOWS:
         if hasattr(wv, 'service_pack_major'):  # python >= 2.7
             sp = wv.service_pack_major or 0
         else:
-            r = re.search("\s\d$", wv[4])
+            r = re.search(r"\s\d$", wv[4])
             if r:
                 sp = int(r.group(0))
             else:
@@ -528,7 +526,7 @@ class ThreadTask(threading.Thread):
 
     def __repr__(self):
         name = self.__class__.__name__
-        return '<%s running=%s at %#x>' % (name, self._running, id(self))
+        return '<{} running={} at {:#x}>'.format(name, self._running, id(self))
 
     def start(self, interval=0.001):
         """Start thread and keep it running until an explicit
@@ -627,7 +625,7 @@ class TestSystemAPIs(unittest.TestCase):
         sproc1.terminate()
         sproc2.terminate()
         gone, alive = test(procs, callback)
-        self.assertEqual(set(l), set([sproc1.pid, sproc2.pid, sproc3.pid]))
+        self.assertEqual(set(l), {sproc1.pid, sproc2.pid, sproc3.pid})
         for p in gone:
             self.assertTrue(hasattr(p, 'returncode'))
 
@@ -664,10 +662,10 @@ class TestSystemAPIs(unittest.TestCase):
         for name in mem._fields:
             value = getattr(mem, name)
             if name != 'percent':
-                self.assertIsInstance(value, (int, long))
+                self.assertIsInstance(value, int)
             if name != 'total':
                 if not value >= 0:
-                    self.fail("%r < 0 (%s)" % (name, value))
+                    self.fail("{!r} < 0 ({})".format(name, value))
                 if value > mem.total:
                     self.fail("%r > total (total=%s, %s=%s)"
                               % (name, mem.total, name, value))
@@ -709,7 +707,7 @@ class TestSystemAPIs(unittest.TestCase):
                 time.sleep(.1)
                 if pid in psutil.pids():
                     self.fail(pid)
-        pids = range(max(pids) + 5000, max(pids) + 6000)
+        pids = list(range(max(pids) + 5000, max(pids) + 6000))
         for pid in pids:
             self.assertFalse(psutil.pid_exists(pid), msg=pid)
 
@@ -764,7 +762,7 @@ class TestSystemAPIs(unittest.TestCase):
                     new_t = getattr(new, field)
                     last_t = getattr(last, field)
                     self.assertGreaterEqual(new_t, last_t,
-                                            msg="%s %s" % (new_t, last_t))
+                                            msg="{} {}".format(new_t, last_t))
                 last = new
 
     def test_sys_cpu_times2(self):
@@ -828,7 +826,7 @@ class TestSystemAPIs(unittest.TestCase):
             self.assertIsNot(percent, -0.0)
             self.assertLessEqual(percent, 100.0 * psutil.cpu_count())
         except AssertionError as err:
-            raise AssertionError("\n%s\nlast=%s\nnew=%s" % (
+            raise AssertionError("\n{}\nlast={}\nnew={}".format(
                 err, pprint.pformat(last_ret), pprint.pformat(new_ret)))
 
     def test_sys_cpu_percent(self):
@@ -1034,7 +1032,7 @@ class TestSystemAPIs(unittest.TestCase):
         # self.assertEqual(sorted(nics.keys()),
         #                  sorted(psutil.net_io_counters(pernic=True).keys()))
 
-        families = set([socket.AF_INET, AF_INET6, psutil.AF_LINK])
+        families = {socket.AF_INET, AF_INET6, psutil.AF_LINK}
         for nic, addrs in nics.items():
             self.assertEqual(len(set(addrs)), len(addrs))
             for addr in addrs:
@@ -1120,7 +1118,7 @@ class TestSystemAPIs(unittest.TestCase):
                 # https://github.com/giampaolo/psutil/issues/338
                 while key[-1].isdigit():
                     key = key[:-1]
-                self.assertNotIn(key, ret.keys())
+                self.assertNotIn(key, list(ret.keys()))
 
     def test_users(self):
         users = psutil.users()
@@ -1326,10 +1324,10 @@ class TestProcess(unittest.TestCase):
         # using a tolerance  of +/- 0.1 seconds.
         # It will fail if the difference between the values is > 0.1s.
         if (max([user_time, utime]) - min([user_time, utime])) > 0.1:
-            self.fail("expected: %s, found: %s" % (utime, user_time))
+            self.fail("expected: {}, found: {}".format(utime, user_time))
 
         if (max([kernel_time, ktime]) - min([kernel_time, ktime])) > 0.1:
-            self.fail("expected: %s, found: %s" % (ktime, kernel_time))
+            self.fail("expected: {}, found: {}".format(ktime, kernel_time))
 
     def test_create_time(self):
         sproc = get_test_subprocess(wait=True)
@@ -1422,13 +1420,13 @@ class TestProcess(unittest.TestCase):
                 self.assertRaises(ValueError, p.ionice, 2, -1)
                 self.assertRaises(ValueError, p.ionice, 4)
                 self.assertRaises(TypeError, p.ionice, 2, "foo")
-                self.assertRaisesRegexp(
+                self.assertRaisesRegex(
                     ValueError, "can't specify value with IOPRIO_CLASS_NONE",
                     p.ionice, psutil.IOPRIO_CLASS_NONE, 1)
-                self.assertRaisesRegexp(
+                self.assertRaisesRegex(
                     ValueError, "can't specify value with IOPRIO_CLASS_IDLE",
                     p.ionice, psutil.IOPRIO_CLASS_IDLE, 1)
-                self.assertRaisesRegexp(
+                self.assertRaisesRegex(
                     ValueError, "'ioclass' argument must be specified",
                     p.ionice, value=1)
             finally:
@@ -1578,7 +1576,7 @@ class TestProcess(unittest.TestCase):
                 elif fname in ('addr', 'perms'):
                     assert value, value
                 else:
-                    self.assertIsInstance(value, (int, long))
+                    self.assertIsInstance(value, int)
                     assert value >= 0, value
 
     def test_memory_percent(self):
@@ -1611,7 +1609,7 @@ class TestProcess(unittest.TestCase):
                 # "/usr/local/bin/python"
                 # We do not want to consider this difference in accuracy
                 # an error.
-                ver = "%s.%s" % (sys.version_info[0], sys.version_info[1])
+                ver = "{}.{}".format(sys.version_info[0], sys.version_info[1])
                 self.assertEqual(exe.replace(ver, ''), PYTHON.replace(ver, ''))
 
     def test_cmdline(self):
@@ -1779,7 +1777,7 @@ class TestProcess(unittest.TestCase):
         p.cpu_affinity(tuple(all_cpus))
         invalid_cpu = [len(psutil.cpu_times(percpu=True)) + 10]
         self.assertRaises(ValueError, p.cpu_affinity, invalid_cpu)
-        self.assertRaises(ValueError, p.cpu_affinity, range(10000, 11000))
+        self.assertRaises(ValueError, p.cpu_affinity, list(range(10000, 11000)))
         self.assertRaises(TypeError, p.cpu_affinity, [0, "1"])
 
     # TODO
@@ -2085,7 +2083,7 @@ class TestProcess(unittest.TestCase):
             except psutil.Error:
                 pass
         # this is the one, now let's make sure there are no duplicates
-        pid = sorted(table.items(), key=lambda x: x[1])[-1][0]
+        pid = sorted(list(table.items()), key=lambda x: x[1])[-1][0]
         p = psutil.Process(pid)
         try:
             c = p.children(recursive=True)
@@ -2173,7 +2171,7 @@ class TestProcess(unittest.TestCase):
                 pass
             else:
                 self.fail(
-                    "NoSuchProcess exception not raised for %r, retval=%s" % (
+                    "NoSuchProcess exception not raised for {!r}, retval={}".format(
                         name, ret))
 
     @unittest.skipUnless(POSIX, 'posix only')
@@ -2280,7 +2278,7 @@ class TestProcess(unittest.TestCase):
             except psutil.AccessDenied:
                 pass
 
-            self.assertRaisesRegexp(
+            self.assertRaisesRegex(
                 ValueError, "preventing sending signal to process with PID 0",
                 p.send_signal, signal.SIGTERM)
 
@@ -2344,14 +2342,14 @@ class TestFetchAllProcesses(unittest.TestCase):
         if POSIX:
             import pwd
             pall = pwd.getpwall()
-            self._uids = set([x.pw_uid for x in pall])
-            self._usernames = set([x.pw_name for x in pall])
+            self._uids = {x.pw_uid for x in pall}
+            self._usernames = {x.pw_name for x in pall}
 
     def test_fetch_all(self):
         valid_procs = 0
-        excluded_names = set([
+        excluded_names = {
             'send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait',
-            'as_dict', 'cpu_percent', 'parent', 'children', 'pid'])
+            'as_dict', 'cpu_percent', 'parent', 'children', 'pid'}
         if LINUX and not RLIMIT_SUPPORT:
             excluded_names.add('rlimit')
         attrs = []
@@ -2397,7 +2395,7 @@ class TestFetchAllProcesses(unittest.TestCase):
                         meth(ret)
                 except Exception as err:
                     s = '\n' + '=' * 70 + '\n'
-                    s += "FAIL: test_%s (proc=%s" % (name, p)
+                    s += "FAIL: test_{} (proc={}".format(name, p)
                     if ret != default:
                         s += ", ret=%s)" % repr(ret)
                     s += ')\n'
@@ -2434,7 +2432,7 @@ class TestFetchAllProcesses(unittest.TestCase):
         self.assertTrue(ret >= 0)
 
     def name(self, ret):
-        self.assertIsInstance(ret, (str, unicode))
+        self.assertIsInstance(ret, (str, str))
         self.assertTrue(ret)
 
     def create_time(self, ret):
@@ -2568,7 +2566,7 @@ class TestFetchAllProcesses(unittest.TestCase):
                 elif fname in ('addr', 'perms'):
                     self.assertTrue(value)
                 else:
-                    self.assertIsInstance(value, (int, long))
+                    self.assertIsInstance(value, int)
                     assert value >= 0, value
 
     def num_handles(self, ret):
@@ -2743,7 +2741,7 @@ class TestMisc(unittest.TestCase):
         self.assertNotEqual(p1, 'foo')
 
     def test_process__hash__(self):
-        s = set([psutil.Process(), psutil.Process()])
+        s = {psutil.Process(), psutil.Process()}
         self.assertEqual(len(s), 1)
 
     def test__all__(self):
@@ -2901,7 +2899,7 @@ class TestExampleScripts(unittest.TestCase):
 
     def assert_syntax(self, exe, args=None):
         exe = os.path.join(EXAMPLES_DIR, exe)
-        with open(exe, 'r') as f:
+        with open(exe) as f:
             src = f.read()
         ast.parse(src)
 
@@ -3004,7 +3002,7 @@ def main():
         tests.append(stc)
 
     for test_class in tests:
-        test_suite.addTest(unittest.makeSuite(test_class))
+        test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(test_class))
     result = unittest.TextTestRunner(verbosity=2).run(test_suite)
     return result.wasSuccessful()
 
diff --git a/python/py/py/_apipkg.py b/python/py/py/_apipkg.py
index a73b8f6d0b..ae24a8b33a 100644
--- a/python/py/py/_apipkg.py
+++ b/python/py/py/_apipkg.py
@@ -77,7 +77,7 @@ class ApiModule(ModuleType):
                 setattr(self, name, val)
         for name, importspec in importspec.items():
             if isinstance(importspec, dict):
-                subname = '%s.%s' % (self.__name__, name)
+                subname = '{}.{}'.format(self.__name__, name)
                 apimod = ApiModule(subname, importspec, implprefix)
                 sys.modules[subname] = apimod
                 setattr(self, name, apimod)
@@ -89,7 +89,7 @@ class ApiModule(ModuleType):
                     modpath = implprefix + modpath
 
                 if not attrname:
-                    subname = '%s.%s' % (self.__name__, name)
+                    subname = '{}.{}'.format(self.__name__, name)
                     apimod = AliasModule(subname, modpath)
                     sys.modules[subname] = apimod
                     if '.' not in name:
@@ -104,8 +104,8 @@ class ApiModule(ModuleType):
         if hasattr(self, '__file__'):
             l.append('from ' + repr(self.__file__))
         if l:
-            return '<ApiModule %r %s>' % (self.__name__, " ".join(l))
-        return '<ApiModule %r>' % (self.__name__,)
+            return '<ApiModule {!r} {}>'.format(self.__name__, " ".join(l))
+        return '<ApiModule {!r}>'.format(self.__name__)
 
     def __makeattr(self, name):
         """lazily compute value for name or raise AttributeError if unknown."""
@@ -164,7 +164,7 @@ def AliasModule(modname, modpath, attrname=None):
             x = modpath
             if attrname:
                 x += "." + attrname
-            return '<AliasModule %r for %r>' % (modname, x)
+            return '<AliasModule {!r} for {!r}>'.format(modname, x)
 
         def __getattribute__(self, name):
             try:
diff --git a/python/py/py/_builtin.py b/python/py/py/_builtin.py
index 52ee9d79ca..ba30137a15 100644
--- a/python/py/py/_builtin.py
+++ b/python/py/py/_builtin.py
@@ -14,7 +14,7 @@ except NameError:
             raise TypeError("argument to reversed() must be a sequence")
         return reversed_iterator(sequence)
 
-    class reversed_iterator(object):
+    class reversed_iterator:
 
         def __init__(self, seq):
             self.seq = seq
@@ -113,127 +113,60 @@ except NameError:
     def callable(obj):
         return hasattr(obj, "__call__")
 
-if sys.version_info >= (3, 0):
-    exec ("print_ = print ; exec_=exec")
-    import builtins
+exec ("print_ = print ; exec_=exec")
+import builtins
 
-    # some backward compatibility helpers
-    _basestring = str
-    def _totext(obj, encoding=None, errors=None):
-        if isinstance(obj, bytes):
-            if errors is None:
-                obj = obj.decode(encoding)
-            else:
-                obj = obj.decode(encoding, errors)
-        elif not isinstance(obj, str):
-            obj = str(obj)
-        return obj
-
-    def _isbytes(x):
-        return isinstance(x, bytes)
-    def _istext(x):
-        return isinstance(x, str)
-
-    text = str
-    bytes = bytes
-
-
-    def _getimself(function):
-        return getattr(function, '__self__', None)
-
-    def _getfuncdict(function):
-        return getattr(function, "__dict__", None)
-
-    def _getcode(function):
-        return getattr(function, "__code__", None)
-
-    def execfile(fn, globs=None, locs=None):
-        if globs is None:
-            back = sys._getframe(1)
-            globs = back.f_globals
-            locs = back.f_locals
-            del back
-        elif locs is None:
-            locs = globs
-        fp = open(fn, "r")
-        try:
-            source = fp.read()
-        finally:
-            fp.close()
-        co = compile(source, fn, "exec", dont_inherit=True)
-        exec_(co, globs, locs)
-
-else:
-    import __builtin__ as builtins
-    _totext = unicode
-    _basestring = basestring
-    text = unicode
-    bytes = str
-    execfile = execfile
-    callable = callable
-    def _isbytes(x):
-        return isinstance(x, str)
-    def _istext(x):
-        return isinstance(x, unicode)
-
-    def _getimself(function):
-        return getattr(function, 'im_self', None)
+# some backward compatibility helpers
+_basestring = str
+def _totext(obj, encoding=None, errors=None):
+    if isinstance(obj, bytes):
+        if errors is None:
+            obj = obj.decode(encoding)
+        else:
+            obj = obj.decode(encoding, errors)
+    elif not isinstance(obj, str):
+        obj = str(obj)
+    return obj
+
+def _isbytes(x):
+    return isinstance(x, bytes)
+def _istext(x):
+    return isinstance(x, str)
+
+text = str
+bytes = bytes
+
+
+def _getimself(function):
+    return getattr(function, '__self__', None)
+
+def _getfuncdict(function):
+    return getattr(function, "__dict__", None)
+
+def _getcode(function):
+    return getattr(function, "__code__", None)
+
+def execfile(fn, globs=None, locs=None):
+    if globs is None:
+        back = sys._getframe(1)
+        globs = back.f_globals
+        locs = back.f_locals
+        del back
+    elif locs is None:
+        locs = globs
+    fp = open(fn)
+    try:
+        source = fp.read()
+    finally:
+        fp.close()
+    co = compile(source, fn, "exec", dont_inherit=True)
+    exec_(co, globs, locs)
 
-    def _getfuncdict(function):
-        return getattr(function, "__dict__", None)
 
-    def _getcode(function):
-        try:
-            return getattr(function, "__code__")
-        except AttributeError:
-            return getattr(function, "func_code", None)
-
-    def print_(*args, **kwargs):
-        """ minimal backport of py3k print statement. """
-        sep = ' '
-        if 'sep' in kwargs:
-            sep = kwargs.pop('sep')
-        end = '\n'
-        if 'end' in kwargs:
-            end = kwargs.pop('end')
-        file = 'file' in kwargs and kwargs.pop('file') or sys.stdout
-        if kwargs:
-            args = ", ".join([str(x) for x in kwargs])
-            raise TypeError("invalid keyword arguments: %s" % args)
-        at_start = True
-        for x in args:
-            if not at_start:
-                file.write(sep)
-            file.write(str(x))
-            at_start = False
-        file.write(end)
-
-    def exec_(obj, globals=None, locals=None):
-        """ minimal backport of py3k exec statement. """
-        __tracebackhide__ = True
-        if globals is None:
-            frame = sys._getframe(1)
-            globals = frame.f_globals
-            if locals is None:
-                locals = frame.f_locals
-        elif locals is None:
-            locals = globals
-        exec2(obj, globals, locals)
-
-if sys.version_info >= (3, 0):
-    def _reraise(cls, val, tb):
-        __tracebackhide__ = True
-        assert hasattr(val, '__traceback__')
-        raise cls.with_traceback(val, tb)
-else:
-    exec ("""
 def _reraise(cls, val, tb):
     __tracebackhide__ = True
-    raise cls, val, tb
-def exec2(obj, globals, locals):
-    __tracebackhide__ = True
-    exec obj in globals, locals
-""")
+    assert hasattr(val, '__traceback__')
+    raise cls.with_traceback(val, tb)
 
 def _tryimport(*names):
     """ return the first successfully imported module. """
diff --git a/python/py/py/_code/_assertionnew.py b/python/py/py/_code/_assertionnew.py
index afb1b31ff0..89fb792bd5 100644
--- a/python/py/py/_code/_assertionnew.py
+++ b/python/py/py/_code/_assertionnew.py
@@ -20,8 +20,8 @@ if sys.platform.startswith("java") and sys.version_info < (2, 5, 2):
               "AugAssign", "Print", "For", "While", "If", "With", "Raise",
               "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom",
               "Exec", "Global", "Expr", "Pass", "Break", "Continue")
-    _expr_nodes = set(getattr(ast, name) for name in _exprs)
-    _stmt_nodes = set(getattr(ast, name) for name in _stmts)
+    _expr_nodes = {getattr(ast, name) for name in _exprs}
+    _stmt_nodes = {getattr(ast, name) for name in _stmts}
     def _is_ast_expr(node):
         return node.__class__ in _expr_nodes
     def _is_ast_stmt(node):
@@ -66,9 +66,9 @@ def getfailure(failure):
         lines = explanation.splitlines()
         if not lines:
             lines.append("")
-        lines[0] += " << %s" % (value,)
+        lines[0] += " << {}".format(value)
         explanation = "\n".join(lines)
-    text = "%s: %s" % (failure.cause[0].__name__, explanation)
+    text = "{}: {}".format(failure.cause[0].__name__, explanation)
     if text.startswith("AssertionError: assert "):
         text = text[16:]
     return text
@@ -148,7 +148,7 @@ class DebugInterpreter(ast.NodeVisitor):
     def visit_Name(self, name):
         explanation, result = self.generic_visit(name)
         # See if the name is local.
-        source = "%r in locals() is not globals()" % (name.id,)
+        source = "{!r} in locals() is not globals()".format(name.id)
         co = self._compile(source)
         try:
             local = self.frame.eval(co)
@@ -165,9 +165,9 @@ class DebugInterpreter(ast.NodeVisitor):
         for op, next_op in zip(comp.ops, comp.comparators):
             next_explanation, next_result = self.visit(next_op)
             op_symbol = operator_map[op.__class__]
-            explanation = "%s %s %s" % (left_explanation, op_symbol,
+            explanation = "{} {} {}".format(left_explanation, op_symbol,
                                         next_explanation)
-            source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,)
+            source = "__exprinfo_left {} __exprinfo_right".format(op_symbol)
             co = self._compile(source)
             try:
                 result = self.frame.eval(co, __exprinfo_left=left_result,
@@ -217,9 +217,9 @@ class DebugInterpreter(ast.NodeVisitor):
         left_explanation, left_result = self.visit(binop.left)
         right_explanation, right_result = self.visit(binop.right)
         symbol = operator_map[binop.op.__class__]
-        explanation = "(%s %s %s)" % (left_explanation, symbol,
+        explanation = "({} {} {})".format(left_explanation, symbol,
                                       right_explanation)
-        source = "__exprinfo_left %s __exprinfo_right" % (symbol,)
+        source = "__exprinfo_left {} __exprinfo_right".format(symbol)
         co = self._compile(source)
         try:
             result = self.frame.eval(co, __exprinfo_left=left_result,
@@ -235,13 +235,13 @@ class DebugInterpreter(ast.NodeVisitor):
         arguments = []
         for arg in call.args:
             arg_explanation, arg_result = self.visit(arg)
-            arg_name = "__exprinfo_%s" % (len(ns),)
+            arg_name = "__exprinfo_{}".format(len(ns))
             ns[arg_name] = arg_result
             arguments.append(arg_name)
             arg_explanations.append(arg_explanation)
         for keyword in call.keywords:
             arg_explanation, arg_result = self.visit(keyword.value)
-            arg_name = "__exprinfo_%s" % (len(ns),)
+            arg_name = "__exprinfo_{}".format(len(ns))
             ns[arg_name] = arg_result
             keyword_source = "%s=%%s" % (keyword.arg)
             arguments.append(keyword_source % (arg_name,))
@@ -250,18 +250,18 @@ class DebugInterpreter(ast.NodeVisitor):
             arg_explanation, arg_result = self.visit(call.starargs)
             arg_name = "__exprinfo_star"
             ns[arg_name] = arg_result
-            arguments.append("*%s" % (arg_name,))
-            arg_explanations.append("*%s" % (arg_explanation,))
+            arguments.append("*{}".format(arg_name))
+            arg_explanations.append("*{}".format(arg_explanation))
         if call.kwargs:
             arg_explanation, arg_result = self.visit(call.kwargs)
             arg_name = "__exprinfo_kwds"
             ns[arg_name] = arg_result
-            arguments.append("**%s" % (arg_name,))
-            arg_explanations.append("**%s" % (arg_explanation,))
+            arguments.append("**{}".format(arg_name))
+            arg_explanations.append("**{}".format(arg_explanation))
         args_explained = ", ".join(arg_explanations)
-        explanation = "%s(%s)" % (func_explanation, args_explained)
+        explanation = "{}({})".format(func_explanation, args_explained)
         args = ", ".join(arguments)
-        source = "__exprinfo_func(%s)" % (args,)
+        source = "__exprinfo_func({})".format(args)
         co = self._compile(source)
         try:
             result = self.frame.eval(co, **ns)
@@ -285,14 +285,14 @@ class DebugInterpreter(ast.NodeVisitor):
         if not isinstance(attr.ctx, ast.Load):
             return self.generic_visit(attr)
         source_explanation, source_result = self.visit(attr.value)
-        explanation = "%s.%s" % (source_explanation, attr.attr)
-        source = "__exprinfo_expr.%s" % (attr.attr,)
+        explanation = "{}.{}".format(source_explanation, attr.attr)
+        source = "__exprinfo_expr.{}".format(attr.attr)
         co = self._compile(source)
         try:
             result = self.frame.eval(co, __exprinfo_expr=source_result)
         except Exception:
             raise Failure(explanation)
-        explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),
+        explanation = "{}\n{{{} = {}.{}\n}}".format(self.frame.repr(result),
                                               self.frame.repr(result),
                                               source_explanation, attr.attr)
         # Check if the attr is from an instance.
@@ -314,7 +314,7 @@ class DebugInterpreter(ast.NodeVisitor):
         if test_explanation.startswith("False\n{False =") and \
                 test_explanation.endswith("\n"):
             test_explanation = test_explanation[15:-2]
-        explanation = "assert %s" % (test_explanation,)
+        explanation = "assert {}".format(test_explanation)
         if not test_result:
             try:
                 raise BuiltinAssertionError
@@ -324,7 +324,7 @@ class DebugInterpreter(ast.NodeVisitor):
 
     def visit_Assign(self, assign):
         value_explanation, value_result = self.visit(assign.value)
-        explanation = "... = %s" % (value_explanation,)
+        explanation = "... = {}".format(value_explanation)
         name = ast.Name("__exprinfo_expr", ast.Load(),
                         lineno=assign.value.lineno,
                         col_offset=assign.value.col_offset)
diff --git a/python/py/py/_code/_assertionold.py b/python/py/py/_code/_assertionold.py
index 4e81fb3ef6..5a623b7835 100644
--- a/python/py/py/_code/_assertionold.py
+++ b/python/py/py/_code/_assertionold.py
@@ -10,7 +10,7 @@ class Failure:
         self.exc, self.value, self.tb = sys.exc_info()
         self.node = node
 
-class View(object):
+class View:
     """View base class.
 
     If C is a subclass of View, then C(x) creates a proxy object around
@@ -86,13 +86,12 @@ class View(object):
             return type('?', tuple(choices), {})
 
     def __repr__(self):
-        return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__)
+        return '{}({!r})'.format(self.__rootclass__.__name__, self.__obj__)
 
 
 def enumsubclasses(cls):
     for subcls in cls.__subclasses__():
-        for subsubclass in enumsubclasses(subcls):
-            yield subsubclass
+        yield from enumsubclasses(subcls)
     yield cls
 
 
@@ -156,7 +155,7 @@ class Name(Interpretable):
             return False
 
     def is_builtin(self, frame):
-        source = '%r not in locals() and %r not in globals()' % (
+        source = '{!r} not in locals() and {!r} not in globals()'.format(
             self.name, self.name)
         try:
             return frame.is_true(frame.eval(source))
@@ -166,7 +165,7 @@ class Name(Interpretable):
             return False
 
     def eval(self, frame):
-        super(Name, self).eval(frame)
+        super().eval(frame)
         if not self.is_local(frame):
             self.explanation = self.name
 
@@ -183,7 +182,7 @@ class Compare(Interpretable):
                     break
             expr2 = Interpretable(expr2)
             expr2.eval(frame)
-            self.explanation = "%s %s %s" % (
+            self.explanation = "{} {} {}".format(
                 expr.explanation, operation, expr2.explanation)
             source = "__exprinfo_left %s __exprinfo_right" % operation
             try:
@@ -316,8 +315,8 @@ class CallFunc(Interpretable):
                 source += argname + ','
                 explanations.append(a.explanation)
             else:
-                source += '%s=%s,' % (keyword, argname)
-                explanations.append('%s=%s' % (keyword, a.explanation))
+                source += '{}={},'.format(keyword, argname)
+                explanations.append('{}={}'.format(keyword, a.explanation))
         if self.star_args:
             star_args = Interpretable(self.star_args)
             star_args.eval(frame)
@@ -332,7 +331,7 @@ class CallFunc(Interpretable):
             vars[argname] = dstar_args.result
             source += '**' + argname + ','
             explanations.append('**' + dstar_args.explanation)
-        self.explanation = "%s(%s)" % (
+        self.explanation = "{}({})".format(
             node.explanation, ', '.join(explanations))
         if source.endswith(','):
             source = source[:-1]
@@ -345,7 +344,7 @@ class CallFunc(Interpretable):
             raise Failure(self)
         if not node.is_builtin(frame) or not self.is_bool(frame):
             r = frame.repr(self.result)
-            self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation)
+            self.explanation = '{}\n{{{} = {}\n}}'.format(r, r, self.explanation)
 
 class Getattr(Interpretable):
     __view__ = ast.Getattr
@@ -360,7 +359,7 @@ class Getattr(Interpretable):
             raise
         except:
             raise Failure(self)
-        self.explanation = '%s.%s' % (expr.explanation, self.attrname)
+        self.explanation = '{}.{}'.format(expr.explanation, self.attrname)
         # if the attribute comes from the instance, its value is interesting
         source = ('hasattr(__exprinfo_expr, "__dict__") and '
                   '%r in __exprinfo_expr.__dict__' % self.attrname)
@@ -373,7 +372,7 @@ class Getattr(Interpretable):
             from_instance = True
         if from_instance:
             r = frame.repr(self.result)
-            self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation)
+            self.explanation = '{}\n{{{} = {}\n}}'.format(r, r, self.explanation)
 
 # == Re-interpretation of full statements ==
 
@@ -442,7 +441,7 @@ def report_failure(e):
         explanation = ", in: " + explanation
     else:
         explanation = ""
-    sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation))
+    sys.stdout.write("{}: {}{}\n".format(e.exc.__name__, e.value, explanation))
 
 def check(s, frame=None):
     if frame is None:
@@ -500,16 +499,16 @@ def getmsg(excinfo):
     source = str(tb.statement).strip()
     x = interpret(source, tb.frame, should_fail=True)
     if not isinstance(x, str):
-        raise TypeError("interpret returned non-string %r" % (x,))
+        raise TypeError("interpret returned non-string {!r}".format(x))
     return x
 
 def getfailure(e):
     explanation = e.node.nice_explanation()
     if str(e.value):
         lines = explanation.split('\n')
-        lines[0] += "  << %s" % (e.value,)
+        lines[0] += "  << {}".format(e.value)
         explanation = '\n'.join(lines)
-    text = "%s: %s" % (e.exc.__name__, explanation)
+    text = "{}: {}".format(e.exc.__name__, explanation)
     if text.startswith('AssertionError: assert '):
         text = text[16:]
     return text
diff --git a/python/py/py/_code/_py2traceback.py b/python/py/py/_code/_py2traceback.py
index d65e27cb73..e624c243ac 100644
--- a/python/py/py/_code/_py2traceback.py
+++ b/python/py/py/_code/_py2traceback.py
@@ -23,7 +23,7 @@ def format_exception_only(etype, value):
 
     # An instance should not have a meaningful value parameter, but
     # sometimes does, particularly for string exceptions, such as
-    # >>> raise string1, string2  # deprecated
+    # >>> raise string1(string2  # deprecated)
     #
     # Clear these out first because issubtype(string1, SyntaxError)
     # would throw another exception and mask the original problem.
@@ -65,12 +65,12 @@ def _format_final_exc_line(etype, value):
     if value is None or not valuestr:
         line = "%s\n" % etype
     else:
-        line = "%s: %s\n" % (etype, valuestr)
+        line = "{}: {}\n".format(etype, valuestr)
     return line
 
 def _some_str(value):
     try:
-        return unicode(value)
+        return str(value)
     except Exception:
         try:
             return str(value)
diff --git a/python/py/py/_code/assertion.py b/python/py/py/_code/assertion.py
index 4ce80c75b1..89824382f0 100644
--- a/python/py/py/_code/assertion.py
+++ b/python/py/py/_code/assertion.py
@@ -82,11 +82,8 @@ class AssertionError(BuiltinAssertionError):
             if not self.args:
                 self.args = (self.msg,)
 
-if sys.version_info > (3, 0):
-    AssertionError.__module__ = "builtins"
-    reinterpret_old = "old reinterpretation not available for py3"
-else:
-    from py._code._assertionold import interpret as reinterpret_old
+AssertionError.__module__ = "builtins"
+reinterpret_old = "old reinterpretation not available for py3"
 if sys.version_info >= (2, 6) or (sys.platform.startswith("java")):
     from py._code._assertionnew import interpret as reinterpret
 else:
diff --git a/python/py/py/_code/code.py b/python/py/py/_code/code.py
index f14c562a29..0b29de99c4 100644
--- a/python/py/py/_code/code.py
+++ b/python/py/py/_code/code.py
@@ -6,12 +6,9 @@ builtin_repr = repr
 
 reprlib = py.builtin._tryimport('repr', 'reprlib')
 
-if sys.version_info[0] >= 3:
-    from traceback import format_exception_only
-else:
-    from py._code._py2traceback import format_exception_only
+from traceback import format_exception_only
 
-class Code(object):
+class Code:
     """ wrapper around Python code objects """
     def __init__(self, rawcode):
         if not hasattr(rawcode, "co_filename"):
@@ -70,7 +67,7 @@ class Code(object):
             argcount += raw.co_flags & CO_VARKEYWORDS
         return raw.co_varnames[:argcount]
 
-class Frame(object):
+class Frame:
     """Wrapper around a Python frame holding f_locals and f_globals
     in which expressions can be evaluated."""
 
@@ -130,7 +127,7 @@ class Frame(object):
                 pass     # this can occur when using Psyco
         return retval
 
-class TracebackEntry(object):
+class TracebackEntry:
     """ a single entry in a traceback """
 
     _repr_style = None
@@ -177,7 +174,7 @@ class TracebackEntry(object):
             source = str(self.statement).strip()
             x = py.code._reinterpret(source, self.frame, should_fail=True)
             if not isinstance(x, str):
-                raise TypeError("interpret returned non-string %r" % (x,))
+                raise TypeError("interpret returned non-string {!r}".format(x))
             self.exprinfo = x
         return self.exprinfo
 
@@ -281,7 +278,7 @@ class Traceback(list):
         return self
 
     def __getitem__(self, key):
-        val = super(Traceback, self).__getitem__(key)
+        val = super().__getitem__(key)
         if isinstance(key, type(slice(0))):
             val = self.__class__(val)
         return val
@@ -296,7 +293,7 @@ class Traceback(list):
             by default this removes all the TracebackItems which are hidden
             (see ishidden() above)
         """
-        return Traceback(filter(fn, self))
+        return Traceback(list(filter(fn, self)))
 
     def getcrashentry(self):
         """ return last non-hidden traceback entry that lead
@@ -335,7 +332,7 @@ class Traceback(list):
 co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
                    '?', 'eval')
 
-class ExceptionInfo(object):
+class ExceptionInfo:
     """ wraps sys.exc_info() objects and offers
         help for navigating the traceback.
     """
@@ -419,10 +416,10 @@ class ExceptionInfo(object):
     def __unicode__(self):
         entry = self.traceback[-1]
         loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
-        return unicode(loc)
+        return str(loc)
 
 
-class FormattedExcinfo(object):
+class FormattedExcinfo:
     """ presenting information about failing Functions and Generators. """
     # for traceback entries
     flow_marker = ">"
@@ -697,7 +694,7 @@ class ReprEntry(TerminalRepr):
             self.reprfileloc.toterminal(tw)
 
     def __str__(self):
-        return "%s\n%s\n%s" % ("\n".join(self.lines),
+        return "{}\n{}\n{}".format("\n".join(self.lines),
                                self.reprlocals,
                                self.reprfileloc)
 
diff --git a/python/py/py/_code/source.py b/python/py/py/_code/source.py
index 3a648e6357..807133727a 100644
--- a/python/py/py/_code/source.py
+++ b/python/py/py/_code/source.py
@@ -1,5 +1,3 @@
-from __future__ import generators
-
 from bisect import bisect_right
 import sys
 import inspect, tokenize
@@ -15,7 +13,7 @@ except ImportError:
     _ast = None
 
 
-class Source(object):
+class Source:
     """ a immutable object holding a source code fragment,
         possibly deindenting it.
     """
@@ -193,14 +191,13 @@ class Source(object):
             if flag & _AST_FLAG:
                 return co
             lines = [(x + "\n") for x in self.lines]
-            if sys.version_info[0] >= 3:
-                # XXX py3's inspect.getsourcefile() checks for a module
-                # and a pep302 __loader__ ... we don't have a module
-                # at code compile-time so we need to fake it here
-                m = ModuleType("_pycodecompile_pseudo_module")
-                py.std.inspect.modulesbyfile[filename] = None
-                py.std.sys.modules[None] = m
-                m.__loader__ = 1
+            # XXX py3's inspect.getsourcefile() checks for a module
+            # and a pep302 __loader__ ... we don't have a module
+            # at code compile-time so we need to fake it here
+            m = ModuleType("_pycodecompile_pseudo_module")
+            py.std.inspect.modulesbyfile[filename] = None
+            py.std.sys.modules[None] = m
+            m.__loader__ = 1
             py.std.linecache.cache[filename] = (1, None, lines, filename)
             return co
 
@@ -242,7 +239,7 @@ def getfslineno(obj):
         if fspath:
             try:
                 _, lineno = findsource(obj)
-            except IOError:
+            except OSError:
                 pass
     else:
         fspath = code.path
diff --git a/python/py/py/_error.py b/python/py/py/_error.py
index 550fb521a0..030a8c20fe 100644
--- a/python/py/py/_error.py
+++ b/python/py/py/_error.py
@@ -30,7 +30,7 @@ _winerrnomap = {
     5: errno.EACCES,  # anything better?
 }
 
-class ErrorMaker(object):
+class ErrorMaker:
     """ lazily provides Exception classes for each possible POSIX errno
         (as defined per the 'errno' module).  All such instances
         subclass EnvironmentError.
@@ -64,7 +64,7 @@ class ErrorMaker(object):
             return func(*args, **kwargs)
         except self.Error:
             raise
-        except (OSError, EnvironmentError):
+        except OSError:
             cls, value, tb = sys.exc_info()
             if not hasattr(value, 'errno'):
                 raise
@@ -81,7 +81,7 @@ class ErrorMaker(object):
                     cls = self._geterrnoclass(_winerrnomap[errno])
                 except KeyError:
                     raise value
-            raise cls("%s%r" % (func.__name__, args))
+            raise cls("{}{!r}".format(func.__name__, args))
             __tracebackhide__ = True
             
 
diff --git a/python/py/py/_iniconfig.py b/python/py/py/_iniconfig.py
index 92b50bd853..9c93b3ed82 100644
--- a/python/py/py/_iniconfig.py
+++ b/python/py/py/_iniconfig.py
@@ -17,7 +17,7 @@ class ParseError(Exception):
     def __str__(self):
         return "%s:%s: %s" %(self.path, self.lineno+1, self.msg)
 
-class SectionWrapper(object):
+class SectionWrapper:
     def __init__(self, config, name):
         self.config = config
         self.name = name
@@ -35,15 +35,14 @@ class SectionWrapper(object):
         section = self.config.sections.get(self.name, [])
         def lineof(key):
             return self.config.lineof(self.name, key)
-        for name in sorted(section, key=lineof):
-            yield name
+        yield from sorted(section, key=lineof)
 
     def items(self):
         for name in self:
             yield name, self[name]
 
 
-class IniConfig(object):
+class IniConfig:
     def __init__(self, path, data=None):
         self.path = str(path) # convenience
         if data is None:
@@ -98,7 +97,7 @@ class IniConfig(object):
                     self._raise(lineno, 'unexpected value continuation')
 
                 if last_data:
-                    data = '%s\n%s' % (last_data, data)
+                    data = '{}\n{}'.format(last_data, data)
                 result.append(last[:-1] + (data,))
         return result
 
diff --git a/python/py/py/_io/capture.py b/python/py/py/_io/capture.py
index bc157ed978..9ec9a8347b 100644
--- a/python/py/py/_io/capture.py
+++ b/python/py/py/_io/capture.py
@@ -8,21 +8,14 @@ try:
 except ImportError:
     from StringIO import StringIO
 
-if sys.version_info < (3,0):
-    class TextIO(StringIO):
-        def write(self, data):
-            if not isinstance(data, unicode):
-                data = unicode(data, getattr(self, '_encoding', 'UTF-8'), 'replace')
-            StringIO.write(self, data)
-else:
-    TextIO = StringIO
+TextIO = StringIO
 
 try:
     from io import BytesIO
 except ImportError:
     class BytesIO(StringIO):
         def write(self, data):
-            if isinstance(data, unicode):
+            if isinstance(data, str):
                 raise TypeError("not a byte value: %r" %(data,))
             StringIO.write(self, data)
 
@@ -105,24 +98,18 @@ def dupfile(f, mode=None, buffering=0, raising=False, encoding=None):
             raise
         return f
     newfd = os.dup(fd)
-    if sys.version_info >= (3,0):
-        if encoding is not None:
-            mode = mode.replace("b", "")
-            buffering = True
-        return os.fdopen(newfd, mode, buffering, encoding, closefd=True)
-    else:
-        f = os.fdopen(newfd, mode, buffering)
-        if encoding is not None:
-            return EncodedFile(f, encoding)
-        return f
+    if encoding is not None:
+        mode = mode.replace("b", "")
+        buffering = True
+    return os.fdopen(newfd, mode, buffering, encoding, closefd=True)
 
-class EncodedFile(object):
+class EncodedFile:
     def __init__(self, _stream, encoding):
         self._stream = _stream
         self.encoding = encoding
 
     def write(self, obj):
-        if isinstance(obj, unicode):
+        if isinstance(obj, str):
             obj = obj.encode(self.encoding)
         elif isinstance(obj, str):
             pass
@@ -137,7 +124,7 @@ class EncodedFile(object):
     def __getattr__(self, name):
         return getattr(self._stream, name)
 
-class Capture(object):
+class Capture:
     def call(cls, func, *args, **kwargs):
         """ return a (res, out, err) tuple where
             out and err represent the output/error output
@@ -350,7 +337,7 @@ class DontReadFromInput:
     hang indefinitely.
     """
     def read(self, *args):
-        raise IOError("reading from stdin while output is captured")
+        raise OSError("reading from stdin while output is captured")
     readline = read
     readlines = read
     __iter__ = read
diff --git a/python/py/py/_io/saferepr.py b/python/py/py/_io/saferepr.py
index 8518290efd..63ecc440fb 100644
--- a/python/py/py/_io/saferepr.py
+++ b/python/py/py/_io/saferepr.py
@@ -47,7 +47,7 @@ class SafeRepr(reprlib.Repr):
                 raise
             except:
                 exc_info = 'unknown'
-            return '<[%s("%s") raised in repr()] %s object at 0x%x>' % (
+            return '<[{}("{}") raised in repr()] {} object at 0x{:x}>'.format(
                 exc_name, exc_info, x.__class__.__name__, id(x))
         else:
             if len(s) > self.maxsize:
diff --git a/python/py/py/_io/terminalwriter.py b/python/py/py/_io/terminalwriter.py
index cef1ff5809..b990f42b42 100644
--- a/python/py/py/_io/terminalwriter.py
+++ b/python/py/py/_io/terminalwriter.py
@@ -116,7 +116,7 @@ def should_do_markup(file):
            and os.environ.get('TERM') != 'dumb' \
            and not (sys.platform.startswith('java') and os._name == 'nt')
 
-class TerminalWriter(object):
+class TerminalWriter:
     _esctable = dict(black=30, red=31, green=32, yellow=33,
                      blue=34, purple=35, cyan=36, white=37,
                      Black=40, Red=41, Green=42, Yellow=43,
@@ -174,7 +174,7 @@ class TerminalWriter(object):
             #         N <= (fullwidth - len(title) - 2) // (2*len(sepchar))
             N = (fullwidth - len(title) - 2) // (2*len(sepchar))
             fill = sepchar * N
-            line = "%s %s %s" % (fill, title, fill)
+            line = "{} {} {}".format(fill, title, fill)
         else:
             # we want len(sepchar)*N <= fullwidth
             # i.e.    N <= fullwidth // len(sepchar)
@@ -245,7 +245,7 @@ class Win32ConsoleWriter(TerminalWriter):
             if oldcolors:
                 SetConsoleTextAttribute(handle, oldcolors)
 
-class WriteFile(object):
+class WriteFile:
     def __init__(self, writemethod, encoding=None):
         self.encoding = encoding
         self._writemethod = writemethod
diff --git a/python/py/py/_log/log.py b/python/py/py/_log/log.py
index ce47e8c754..004a0cb0f0 100644
--- a/python/py/py/_log/log.py
+++ b/python/py/py/_log/log.py
@@ -16,7 +16,7 @@ XXX implement this API: (maybe put it into slogger.py?)
 """
 import py, sys
 
-class Message(object):
+class Message:
     def __init__(self, keywords, args):
         self.keywords = keywords
         self.args = args
@@ -31,7 +31,7 @@ class Message(object):
         return self.prefix() + self.content()
 
 
-class Producer(object):
+class Producer:
     """ (deprecated) Log producer API which sends messages to be logged
         to a 'consumer' object, which then prints them to stdout,
         stderr, files, etc. Used extensively by PyPy-1.1.
@@ -92,15 +92,15 @@ class KeywordMapper:
         """ set a consumer for a set of keywords. """
         # normalize to tuples
         if isinstance(keywords, str):
-            keywords = tuple(filter(None, keywords.split()))
+            keywords = tuple([_f for _f in keywords.split() if _f])
         elif hasattr(keywords, '_keywords'):
             keywords = keywords._keywords
         elif not isinstance(keywords, tuple):
-            raise TypeError("key %r is not a string or tuple" % (keywords,))
+            raise TypeError("key {!r} is not a string or tuple".format(keywords))
         if consumer is not None and not py.builtin.callable(consumer):
             if not hasattr(consumer, 'write'):
                 raise TypeError(
-                    "%r should be None, callable or file-like" % (consumer,))
+                    "{!r} should be None, callable or file-like".format(consumer))
             consumer = File(consumer)
         self.keywords2consumer[keywords] = consumer
 
@@ -122,7 +122,7 @@ def getstate():
 # Consumers
 #
 
-class File(object):
+class File:
     """ log consumer wrapping a file(-like) object """
     def __init__(self, f):
         assert hasattr(f, 'write')
@@ -135,7 +135,7 @@ class File(object):
         if hasattr(self._file, 'flush'):
             self._file.flush()
 
-class Path(object):
+class Path:
     """ log consumer that opens and writes to a Path """
     def __init__(self, filename, append=False,
                  delayed_create=False, buffering=False):
diff --git a/python/py/py/_path/cacheutil.py b/python/py/py/_path/cacheutil.py
index 9922504750..26a519c93d 100644
--- a/python/py/py/_path/cacheutil.py
+++ b/python/py/py/_path/cacheutil.py
@@ -10,7 +10,7 @@ methods and allow configuration when instantiating the cache class.
 """
 from time import time as gettime
 
-class BasicCache(object):
+class BasicCache:
     def __init__(self, maxentries=128):
         self.maxentries = maxentries
         self.prunenum = int(maxentries - maxentries/8)
@@ -75,7 +75,7 @@ class BuildcostAccessCache(BasicCache):
         return WeightedCountingEntry(val, end-start)
 
 
-class WeightedCountingEntry(object):
+class WeightedCountingEntry:
     def __init__(self, value, oneweight):
         self._value = value
         self.weight = self._oneweight = oneweight
@@ -89,7 +89,7 @@ class AgingCache(BasicCache):
     """ This cache prunes out cache entries that are too old.
     """
     def __init__(self, maxentries=128, maxseconds=10.0):
-        super(AgingCache, self).__init__(maxentries)
+        super().__init__(maxentries)
         self.maxseconds = maxseconds
 
     def _getentry(self, key):
@@ -104,7 +104,7 @@ class AgingCache(BasicCache):
         entry = AgingEntry(val, gettime() + self.maxseconds)
         return entry
 
-class AgingEntry(object):
+class AgingEntry:
     def __init__(self, value, expirationtime):
         self.value = value
         self.weight = expirationtime
diff --git a/python/py/py/_path/common.py b/python/py/py/_path/common.py
index d407434cb2..509ddf6a32 100644
--- a/python/py/py/_path/common.py
+++ b/python/py/py/_path/common.py
@@ -59,7 +59,7 @@ class Checkers:
                         pass
             if meth is None:
                 raise TypeError(
-                    "no %r checker available for %r" % (name, self.path))
+                    "no {!r} checker available for {!r}".format(name, self.path))
             try:
                 if py.code.getrawcode(meth).co_argcount > 1:
                     if (not meth(value)) ^ invert:
@@ -84,7 +84,7 @@ class Checkers:
 class NeverRaised(Exception):
     pass
 
-class PathBase(object):
+class PathBase:
     """ shared implementation for filesystem path objects."""
     Checkers = Checkers
 
@@ -329,8 +329,7 @@ newline will be removed from the end of each line. """
 
             sort if True will sort entries within each directory level.
         """
-        for x in Visitor(fil, rec, ignore, bf, sort).gen(self):
-            yield x
+        yield from Visitor(fil, rec, ignore, bf, sort).gen(self)
 
     def _sortlist(self, res, sort):
         if sort:
diff --git a/python/py/py/_path/local.py b/python/py/py/_path/local.py
index d569404ec2..eef0cbe40b 100644
--- a/python/py/py/_path/local.py
+++ b/python/py/py/_path/local.py
@@ -1,7 +1,6 @@
 """
 local path implementation.
 """
-from __future__ import with_statement
 
 from contextlib import contextmanager
 import sys, os, re, atexit, io
@@ -12,13 +11,10 @@ from stat import S_ISLNK, S_ISDIR, S_ISREG
 
 from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname
 
-if sys.version_info > (3,0):
-    def map_as_list(func, iter):
-        return list(map(func, iter))
-else:
-    map_as_list = map
+def map_as_list(func, iter):
+    return list(map(func, iter))
 
-class Stat(object):
+class Stat:
     def __getattr__(self, name):
         return getattr(self._osstatresult, "st_" + name)
 
@@ -279,7 +275,7 @@ class LocalPath(FSBase):
         res = []
         parts = self.strpath.split(self.sep)
 
-        args = filter(None, spec.split(',') )
+        args = [_f for _f in spec.split(',') if _f]
         append = res.append
         for name in args:
             if name == 'drive':
@@ -312,7 +308,7 @@ class LocalPath(FSBase):
             if args:
                 path = path.join(*args)
             return path
-        return super(LocalPath, self).dirpath(*args, **kwargs)
+        return super().dirpath(*args, **kwargs)
 
     def join(self, *args, **kwargs):
         """ return a new path by appending all 'args' as path
@@ -368,7 +364,7 @@ class LocalPath(FSBase):
                 return not kw["dir"] ^ isdir(self.strpath)
             if "file" in kw:
                 return not kw["file"] ^ isfile(self.strpath)
-        return super(LocalPath, self).check(**kw)
+        return super().check(**kw)
 
     _patternchars = set("*?[" + os.path.sep)
     def listdir(self, fil=None, sort=None):
@@ -586,7 +582,7 @@ class LocalPath(FSBase):
             if rec is True perform recursively.
         """
         if not isinstance(mode, int):
-            raise TypeError("mode %r must be an integer" % (mode,))
+            raise TypeError("mode {!r} must be an integer".format(mode))
         if rec:
             for x in self.visit(rec=rec):
                 py.error.checked_call(os.chmod, str(x), mode)
diff --git a/python/py/py/_path/svnurl.py b/python/py/py/_path/svnurl.py
index 78d71317ac..e6dc33731b 100644
--- a/python/py/py/_path/svnurl.py
+++ b/python/py/py/_path/svnurl.py
@@ -4,6 +4,7 @@ command 'svn'. This modules aims to work with svn 1.3 and higher
 but might also interact well with earlier versions.
 """
 
+from __future__ import print_function
 import os, sys, time, re
 import py
 from py import path, process
@@ -37,7 +38,7 @@ class SvnCommandPath(svncommon.SvnPathBase):
         if self.rev == -1:
             return 'svnurl(%r)' % self.strpath
         else:
-            return 'svnurl(%r, %r)' % (self.strpath, self.rev)
+            return 'svnurl({!r}, {!r})'.format(self.strpath, self.rev)
 
     def _svnwithrev(self, cmd, *args):
         """ execute an svn command, append our own url and revision """
@@ -56,7 +57,7 @@ class SvnCommandPath(svncommon.SvnPathBase):
         # fixing the locale because we can't otherwise parse
         string = " ".join(l)
         if DEBUG:
-            print("execing %s" % string)
+            print(("execing %s" % string))
         out = self._svncmdexecauth(string)
         return out
 
@@ -98,13 +99,13 @@ class SvnCommandPath(svncommon.SvnPathBase):
     def open(self, mode='r'):
         """ return an opened file with the given mode. """
         if mode not in ("r", "rU",):
-            raise ValueError("mode %r not supported" % (mode,))
+            raise ValueError("mode {!r} not supported".format(mode))
         assert self.check(file=1) # svn cat returns an empty file otherwise
         if self.rev is None:
-            return self._svnpopenauth('svn cat "%s"' % (
-                                      self._escape(self.strpath), ))
+            return self._svnpopenauth('svn cat "{}"'.format(
+                                      self._escape(self.strpath)))
         else:
-            return self._svnpopenauth('svn cat -r %s "%s"' % (
+            return self._svnpopenauth('svn cat -r {} "{}"'.format(
                                       self.rev, self._escape(self.strpath)))
 
     def dirpath(self, *args, **kwargs):
@@ -162,11 +163,11 @@ checkin message msg."""
             py.path.local instance
         """
         topath = py.path.local(topath)
-        args = ['"%s"' % (self._escape(self),),
-                '"%s"' % (self._escape(topath),)]
+        args = ['"{}"'.format(self._escape(self)),
+                '"{}"'.format(self._escape(topath))]
         if self.rev is not None:
             args = ['-r', str(self.rev)] + args
-        self._svncmdexecauth('svn export %s' % (' '.join(args),))
+        self._svncmdexecauth('svn export {}'.format(' '.join(args)))
         return topath
 
     def ensure(self, *args, **kwargs):
@@ -192,7 +193,7 @@ checkin message msg."""
         tempdir = py.path.local.mkdtemp()
         try:
             tempdir.ensure(tocreate, dir=dir)
-            cmd = 'svn import -m "%s" "%s" "%s"' % (
+            cmd = 'svn import -m "{}" "{}" "{}"'.format(
                     "ensure %s" % self._escape(tocreate),
                     self._escape(tempdir.join(basename)),
                     x.join(basename)._encodedurl())
@@ -293,14 +294,14 @@ if verbose is True, then the LogEntry instances also know which files changed.
         if rev_start == "HEAD" and rev_end == 1:
             rev_opt = ""
         else:
-            rev_opt = "-r %s:%s" % (rev_start, rev_end)
+            rev_opt = "-r {}:{}".format(rev_start, rev_end)
         verbose_opt = verbose and "-v" or ""
         xmlpipe =  self._svnpopenauth('svn log --xml %s %s "%s"' %
                                       (rev_opt, verbose_opt, self.strpath))
         from xml.dom import minidom
         tree = minidom.parse(xmlpipe)
         result = []
-        for logentry in filter(None, tree.firstChild.childNodes):
+        for logentry in [_f for _f in tree.firstChild.childNodes if _f]:
             if logentry.nodeType == logentry.ELEMENT_NODE:
                 result.append(svncommon.LogEntry(logentry))
         return result
@@ -315,7 +316,7 @@ class InfoSvnCommand:
     # locked, see 'svn help ls'
     lspattern = re.compile(
         r'^ *(?P<rev>\d+) +(?P<author>.+?) +(0? *(?P<size>\d+))? '
-            '*(?P<date>\w+ +\d{2} +[\d:]+) +(?P<file>.*)$')
+            r'*(?P<date>\w+ +\d{2} +[\d:]+) +(?P<file>.*)$')
     def __init__(self, line):
         # this is a typical line from 'svn ls http://...'
         #_    1127      jum        0 Jul 13 15:28 branch/
diff --git a/python/py/py/_path/svnwc.py b/python/py/py/_path/svnwc.py
index 00d3b4bbaf..66d9110f2d 100644
--- a/python/py/py/_path/svnwc.py
+++ b/python/py/py/_path/svnwc.py
@@ -115,7 +115,7 @@ def checkbadchars(url):
         # only check for bad chars in the non-protocol parts
         if (_check_for_bad_chars(host, ALLOWED_CHARS_HOST) \
             or _check_for_bad_chars(uripath, ALLOWED_CHARS)):
-            raise ValueError("bad char in %r" % (url, ))
+            raise ValueError("bad char in {!r}".format(url))
 
 
 #_______________________________________________________________
@@ -270,7 +270,7 @@ class SvnPathBase(common.PathBase):
     #        except (IOError, process.cmdexec.Error):
     #            break
     #    if rev is None:
-    #        raise IOError, "could not determine newest repo revision for %s" % self
+    #        raise IOError("could not determine newest repo revision for %s" % self)
     #    return rev
 
     class Checkers(common.Checkers):
@@ -327,7 +327,7 @@ def fixlocale():
     return ''
 
 # some nasty chunk of code to solve path and url conversion and quoting issues
-ILLEGAL_CHARS = '* | \ / : < > ? \t \n \x0b \x0c \r'.split(' ')
+ILLEGAL_CHARS = '* | \\ / : < > ? \t \n \x0b \x0c \r'.split(' ')
 if os.sep in ILLEGAL_CHARS:
     ILLEGAL_CHARS.remove(os.sep)
 ISWINDOWS = sys.platform == 'win32'
@@ -341,15 +341,15 @@ def _check_path(path):
             raise ValueError('path may not contain a colon (:)')
     for char in sp:
         if char not in string.printable or char in illegal:
-            raise ValueError('illegal character %r in path' % (char,))
+            raise ValueError('illegal character {!r} in path'.format(char))
 
 def path_to_fspath(path, addat=True):
     _check_path(path)
     sp = path.strpath
     if addat and path.rev != -1:
-        sp = '%s@%s' % (sp, path.rev)
+        sp = '{}@{}'.format(sp, path.rev)
     elif addat:
-        sp = '%s@HEAD' % (sp,)
+        sp = '{}@HEAD'.format(sp)
     return sp
 
 def url_from_path(path):
@@ -359,19 +359,19 @@ def url_from_path(path):
         match = _reg_allow_disk.match(fspath)
         fspath = fspath.replace('\\', '/')
         if match.group(1):
-            fspath = '/%s%s' % (match.group(1).replace('\\', '/'),
+            fspath = '/{}{}'.format(match.group(1).replace('\\', '/'),
                                 quote(fspath[len(match.group(1)):]))
         else:
             fspath = quote(fspath)
     else:
         fspath = quote(fspath)
     if path.rev != -1:
-        fspath = '%s@%s' % (fspath, path.rev)
+        fspath = '{}@{}'.format(fspath, path.rev)
     else:
-        fspath = '%s@HEAD' % (fspath,)
-    return 'file://%s' % (fspath,)
+        fspath = '{}@HEAD'.format(fspath)
+    return 'file://{}'.format(fspath)
 
-class SvnAuth(object):
+class SvnAuth:
     """ container for auth information for Subversion """
     def __init__(self, username, password, cache_auth=True, interactive=True):
         self.username = username
@@ -384,9 +384,9 @@ class SvnAuth(object):
         passwd = self.password.replace('"', '\\"')
         ret = []
         if uname:
-            ret.append('--username="%s"' % (uname,))
+            ret.append('--username="{}"'.format(uname))
         if passwd:
-            ret.append('--password="%s"' % (passwd,))
+            ret.append('--password="{}"'.format(passwd))
         if not self.cache_auth:
             ret.append('--no-auth-cache')
         if not self.interactive:
@@ -413,7 +413,7 @@ class SvnWCCommandPath(common.PathBase):
             wcpath = wcpath.localpath
         if _check_for_bad_chars(str(wcpath),
                                           ALLOWED_CHARS):
-            raise ValueError("bad char in wcpath %s" % (wcpath, ))
+            raise ValueError("bad char in wcpath {}".format(wcpath))
         self.localpath = py.path.local(wcpath)
         self.auth = auth
         return self
@@ -639,11 +639,11 @@ class SvnWCCommandPath(common.PathBase):
             updates = ''
 
         try:
-            cmd = 'status -v --xml --no-ignore %s %s %s' % (
+            cmd = 'status -v --xml --no-ignore {} {} {}'.format(
                     updates, rec, externals)
             out = self._authsvn(cmd)
         except py.process.cmdexec.Error:
-            cmd = 'status -v --no-ignore %s %s %s' % (
+            cmd = 'status -v --no-ignore {} {} {}'.format(
                     updates, rec, externals)
             out = self._authsvn(cmd)
             rootstatus = WCStatus(self).fromstring(out, self)
@@ -683,7 +683,7 @@ class SvnWCCommandPath(common.PathBase):
     def commit(self, msg='', rec=1):
         """ commit with support for non-recursive commits """
         # XXX i guess escaping should be done better here?!?
-        cmd = 'commit -m "%s" --force-log' % (msg.replace('"', '\\"'),)
+        cmd = 'commit -m "{}" --force-log'.format(msg.replace('"', '\\"'))
         if not rec:
             cmd += ' -N'
         out = self._authsvn(cmd)
@@ -788,7 +788,7 @@ recursively. """
             if py.std.sys.platform != 'win32':
                 if info.path != self.localpath:
                     raise py.error.ENOENT(self, "not a versioned resource:" +
-                            " %s != %s" % (info.path, self.localpath))
+                            " {} != {}".format(info.path, self.localpath))
             cache.info[self] = info
         return info
 
@@ -850,7 +850,7 @@ if verbose is True, then the LogEntry instances also know which files changed.
         if rev_start == "HEAD" and rev_end == 1:
                 rev_opt = ""
         else:
-            rev_opt = "-r %s:%s" % (rev_start, rev_end)
+            rev_opt = "-r {}:{}".format(rev_start, rev_end)
         verbose_opt = verbose and "-v" or ""
         locale_env = fixlocale()
         # some blather on stderr
@@ -859,7 +859,7 @@ if verbose is True, then the LogEntry instances also know which files changed.
         #                                   'svn log --xml %s %s %s "%s"' % (
         #                                    rev_opt, verbose_opt, auth_opt,
         #                                    self.strpath))
-        cmd = locale_env + 'svn log --xml %s %s %s "%s"' % (
+        cmd = locale_env + 'svn log --xml {} {} {} "{}"'.format(
             rev_opt, verbose_opt, auth_opt, self.strpath)
 
         popen = subprocess.Popen(cmd,
@@ -875,7 +875,7 @@ if verbose is True, then the LogEntry instances also know which files changed.
         except ExpatError:
             raise ValueError('no such revision')
         result = []
-        for logentry in filter(None, tree.firstChild.childNodes):
+        for logentry in [_f for _f in tree.firstChild.childNodes if _f]:
             if logentry.nodeType == logentry.ELEMENT_NODE:
                 result.append(LogEntry(logentry))
         return result
@@ -913,7 +913,7 @@ class WCStatus:
             if name not in kw or kw[name]:
                 for path in getattr(self, name):
                     d[path] = 1
-        l = d.keys()
+        l = list(d.keys())
         if sort:
             l.sort()
         return l
@@ -1151,7 +1151,7 @@ class InfoSvnWCCommand:
             self.url = d['url']
         except KeyError:
             raise  ValueError("Not a versioned resource")
-            #raise ValueError, "Not a versioned resource %r" % path
+            #raise ValueError("Not a versioned resource %r" % path)
         self.kind = d['nodekind'] == 'directory' and 'dir' or d['nodekind']
         try:
             self.rev = int(d['revision'])
@@ -1215,7 +1215,7 @@ def importxml(cache=[]):
 class LogEntry:
     def __init__(self, logentry):
         self.rev = int(logentry.getAttribute('revision'))
-        for lpart in filter(None, logentry.childNodes):
+        for lpart in [_f for _f in logentry.childNodes if _f]:
             if lpart.nodeType == lpart.ELEMENT_NODE:
                 if lpart.nodeName == 'author':
                     self.author = lpart.firstChild.nodeValue
@@ -1230,7 +1230,7 @@ class LogEntry:
                     self.date = parse_apr_time(timestr)
                 elif lpart.nodeName == 'paths':
                     self.strpaths = []
-                    for ppart in filter(None, lpart.childNodes):
+                    for ppart in [_f for _f in lpart.childNodes if _f]:
                         if ppart.nodeType == ppart.ELEMENT_NODE:
                             self.strpaths.append(PathEntry(ppart))
     def __repr__(self):
diff --git a/python/py/py/_process/cmdexec.py b/python/py/py/_process/cmdexec.py
index f83a249402..31296d94ca 100644
--- a/python/py/py/_process/cmdexec.py
+++ b/python/py/py/_process/cmdexec.py
@@ -21,8 +21,8 @@ def cmdexec(cmd):
             default_encoding = sys.getdefaultencoding() # jython may not have it
         except AttributeError:
             default_encoding = sys.stdout.encoding or 'UTF-8'
-        out = unicode(out, process.stdout.encoding or default_encoding)
-        err = unicode(err, process.stderr.encoding or default_encoding)
+        out = str(out, process.stdout.encoding or default_encoding)
+        err = str(err, process.stderr.encoding or default_encoding)
     status = process.poll()
     if status:
         raise ExecutionFailed(status, status, cmd, out, err)
diff --git a/python/py/py/_process/forkedfunc.py b/python/py/py/_process/forkedfunc.py
index 1c28530688..f334ea6004 100644
--- a/python/py/py/_process/forkedfunc.py
+++ b/python/py/py/_process/forkedfunc.py
@@ -1,4 +1,3 @@
-
 """
     ForkedFunc provides a way to run a function in a forked process
     and get at its return value, stdout and stderr output as well
@@ -111,7 +110,7 @@ class ForkedFunc:
             self._removetemp()
 
 
-class Result(object):
+class Result:
     def __init__(self, exitstatus, signal, retval, stdout, stderr):
         self.exitstatus = exitstatus
         self.signal = signal
diff --git a/python/py/py/_std.py b/python/py/py/_std.py
index 97a9853323..0a91d91cb5 100644
--- a/python/py/py/_std.py
+++ b/python/py/py/_std.py
@@ -1,6 +1,6 @@
 import sys
 
-class Std(object):
+class Std:
     """ makes top-level python modules available as an attribute,
         importing them on first access.
     """
diff --git a/python/py/py/_xmlgen.py b/python/py/py/_xmlgen.py
index 2ffcaa14b8..6e4150d92d 100644
--- a/python/py/py/_xmlgen.py
+++ b/python/py/py/_xmlgen.py
@@ -6,17 +6,12 @@ by using simple python objects.
 """
 import sys, re
 
-if sys.version_info >= (3,0):
-    def u(s):
-        return s
-    def unicode(x, errors=None):
-        if hasattr(x, '__unicode__'):
-            return x.__unicode__()
-        return str(x)
-else:
-    def u(s):
-        return unicode(s)
-    unicode = unicode
+def u(s):
+    return s
+def str(x, errors=None):
+    if hasattr(x, '__unicode__'):
+        return x.__unicode__()
+    return str(x)
 
 
 class NamespaceMetaclass(type):
@@ -36,19 +31,19 @@ class NamespaceMetaclass(type):
         return cls
 
 class Tag(list):
-    class Attr(object):
+    class Attr:
         def __init__(self, **kwargs):
             self.__dict__.update(kwargs)
 
     def __init__(self, *args, **kwargs):
-        super(Tag, self).__init__(args)
+        super().__init__(args)
         self.attr = self.Attr(**kwargs)
 
     def __unicode__(self):
-        return self.unicode(indent=0)
+        return self.str(indent=0)
     __str__ = __unicode__
 
-    def unicode(self, indent=2):
+    def str(self, indent=2):
         l = []
         SimpleUnicodeVisitor(l.append, indent).visit(self)
         return u("").join(l)
@@ -64,7 +59,7 @@ Namespace = NamespaceMetaclass('Namespace', (object, ), {
 })
 
 class HtmlTag(Tag):
-    def unicode(self, indent=2):
+    def str(self, indent=2):
         l = []
         HtmlVisitor(l.append, indent, shortempty=False).visit(self)
         return u("").join(l)
@@ -73,7 +68,7 @@ class HtmlTag(Tag):
 class html(Namespace):
     __tagclass__ = HtmlTag
     __stickyname__ = True
-    __tagspec__ = dict([(x,1) for x in (
+    __tagspec__ = {x:1 for x in (
         'a,abbr,acronym,address,applet,area,b,bdo,big,blink,'
         'blockquote,body,br,button,caption,center,cite,code,col,'
         'colgroup,comment,dd,del,dfn,dir,div,dl,dt,em,embed,'
@@ -84,22 +79,22 @@ class html(Namespace):
         'select,small,span,strike,strong,style,sub,sup,table,'
         'tbody,td,textarea,tfoot,th,thead,title,tr,tt,u,ul,xmp,'
         'base,basefont,frame,hr,isindex,param,samp,var'
-    ).split(',') if x])
+    ).split(',') if x}
 
-    class Style(object):
+    class Style:
         def __init__(self, **kw):
             for x, y in kw.items():
                 x = x.replace('_', '-')
                 setattr(self, x, y)
 
 
-class raw(object):
+class raw:
     """just a box that can contain a unicode string that will be
     included directly in the output"""
     def __init__(self, uniobj):
         self.uniobj = uniobj
 
-class SimpleUnicodeVisitor(object):
+class SimpleUnicodeVisitor:
     """ recursive visitor to write unicode. """
     def __init__(self, write, indent=0, curindent=0, shortempty=True):
         self.write = write
@@ -129,7 +124,7 @@ class SimpleUnicodeVisitor(object):
     # to avoid clashes with the tag name object
     def __object(self, obj):
         #self.write(obj)
-        self.write(escape(unicode(obj)))
+        self.write(escape(str(obj)))
 
     def raw(self, obj):
         self.write(obj.uniobj)
@@ -186,8 +181,8 @@ class SimpleUnicodeVisitor(object):
             if isinstance(value, raw):
                 insert = value.uniobj
             else:
-                insert = escape(unicode(value))
-            return ' %s="%s"' % (name, insert)
+                insert = escape(str(value))
+            return ' {}="{}"'.format(name, insert)
 
     def getstyle(self, tag):
         """ return attribute list suitable for styling. """
@@ -209,20 +204,20 @@ class SimpleUnicodeVisitor(object):
 
 class HtmlVisitor(SimpleUnicodeVisitor):
 
-    single = dict([(x, 1) for x in
+    single = {x: 1 for x in
                 ('br,img,area,param,col,hr,meta,link,base,'
-                    'input,frame').split(',')])
-    inline = dict([(x, 1) for x in
+                    'input,frame').split(',')}
+    inline = {x: 1 for x in
                 ('a abbr acronym b basefont bdo big br cite code dfn em font '
                  'i img input kbd label q s samp select small span strike '
-                 'strong sub sup textarea tt u var'.split(' '))])
+                 'strong sub sup textarea tt u var'.split(' '))}
 
     def repr_attribute(self, attrs, name):
         if name == 'class_':
             value = getattr(attrs, name)
             if value is None:
                 return
-        return super(HtmlVisitor, self).repr_attribute(attrs, name)
+        return super().repr_attribute(attrs, name)
 
     def _issingleton(self, tagname):
         return tagname in self.single
@@ -237,7 +232,7 @@ class _escape:
             u('"') : u('&quot;'), u('<') : u('&lt;'), u('>') : u('&gt;'),
             u('&') : u('&amp;'), u("'") : u('&apos;'),
             }
-        self.charef_rex = re.compile(u("|").join(self.escape.keys()))
+        self.charef_rex = re.compile(u("|").join(list(self.escape.keys())))
 
     def _replacer(self, match):
         return self.escape[match.group(0)]
@@ -245,9 +240,9 @@ class _escape:
     def __call__(self, ustring):
         """ xml-escape the given unicode string. """
         try:
-            ustring = unicode(ustring)
+            ustring = str(ustring)
         except UnicodeDecodeError:
-            ustring = unicode(ustring, 'utf-8', errors='replace')
+            ustring = str(ustring, 'utf-8', errors='replace')
         return self.charef_rex.sub(self._replacer, ustring)
 
 escape = _escape()
diff --git a/python/pyasn1-modules/pyasn1_modules/pem.py b/python/pyasn1-modules/pyasn1_modules/pem.py
index d8d815873e..80da400235 100644
--- a/python/pyasn1-modules/pyasn1_modules/pem.py
+++ b/python/pyasn1-modules/pyasn1_modules/pem.py
@@ -5,10 +5,8 @@ stSpam, stHam, stDump = 0, 1, 2
 # The markers parameters is in form ('start1', 'stop1'), ('start2', 'stop2')...
 # Return is (marker-index, substrate)
 def readPemBlocksFromFile(fileObj, *markers):
-    startMarkers = dict(map(lambda x: (x[1],x[0]),
-                            enumerate(map(lambda x: x[0], markers))))
-    stopMarkers = dict(map(lambda x: (x[1],x[0]),
-                           enumerate(map(lambda x: x[1], markers))))
+    startMarkers = dict([(x[1],x[0]) for x in enumerate([x[0] for x in markers])])
+    stopMarkers = dict([(x[1],x[0]) for x in enumerate([x[1] for x in markers])])
     idx = -1; substrate = ''
     state = stSpam
     while 1:
@@ -31,7 +29,7 @@ def readPemBlocksFromFile(fileObj, *markers):
             if sys.version_info[0] <= 2:
                 substrate = ''.join([ base64.b64decode(x) for x in certLines ])
             else:
-                substrate = ''.encode().join([ base64.b64decode(x.encode()) for x in certLines ])
+                substrate = b''.join([ base64.b64decode(x.encode()) for x in certLines ])
             break
     return idx, substrate
 
@@ -46,6 +44,6 @@ def readBase64FromFile(fileObj):
     if sys.version_info[0] <= 2:
         return ''.join([ base64.b64decode(x) for x in fileObj.readlines() ])
     else:
-        return ''.encode().join(
+        return b''.join(
             [ base64.b64decode(x.encode()) for x in fileObj.readlines() ]
         )
diff --git a/python/pyasn1-modules/setup.py b/python/pyasn1-modules/setup.py
index b7530caa8b..3ce106b000 100644
--- a/python/pyasn1-modules/setup.py
+++ b/python/pyasn1-modules/setup.py
@@ -6,6 +6,7 @@
    data structures (X.509, PKCS etc.).
 """
 
+from __future__ import print_function
 classifiers = """\
 Development Status :: 5 - Production/Stable
 Environment :: Console
diff --git a/python/pyasn1-modules/tools/cmpdump.py b/python/pyasn1-modules/tools/cmpdump.py
index 74c4f77a4e..58806ee0e5 100755
--- a/python/pyasn1-modules/tools/cmpdump.py
+++ b/python/pyasn1-modules/tools/cmpdump.py
@@ -1,6 +1,7 @@
 #!/usr/bin/python
 # Read ASN.1/PEM CMP message on stdin, parse into
 # plain text, then build substrate from it
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc4210, pem
 from pyasn1 import debug
@@ -9,8 +10,8 @@ import sys
 if len(sys.argv) == 2 and sys.argv[1] == '-d':
     debug.setLogger(debug.Debug('all'))
 elif len(sys.argv) != 1:
-    print("""Usage:
-$ cat cmp.pem | %s [-d]""" % sys.argv[0])
+    print(("""Usage:
+$ cat cmp.pem | %s [-d]""" % sys.argv[0]))
     sys.exit(-1)
     
 pkiMessage = rfc4210.PKIMessage()
@@ -21,7 +22,7 @@ if not substrate:
         
 pkiMsg, rest = decoder.decode(substrate, asn1Spec=pkiMessage)
 
-print(pkiMsg.prettyPrint())
+print((pkiMsg.prettyPrint()))
 
 assert encoder.encode(pkiMsg, defMode=False) == substrate or \
        encoder.encode(pkiMsg, defMode=True) == substrate, \
diff --git a/python/pyasn1-modules/tools/crldump.py b/python/pyasn1-modules/tools/crldump.py
index d4b0a547c6..6f61dcc119 100755
--- a/python/pyasn1-modules/tools/crldump.py
+++ b/python/pyasn1-modules/tools/crldump.py
@@ -4,13 +4,14 @@
 # original wire format.
 # CRL can be generated with "openssl openssl ca -gencrl ..." commands.
 #
+from __future__ import print_function
 from pyasn1_modules import rfc2459, pem
 from pyasn1.codec.der import encoder, decoder
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat crl.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat crl.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 asn1Spec = rfc2459.CertificateList()
@@ -27,7 +28,7 @@ while 1:
 
     if rest: substrate = substrate[:-len(rest)]
         
-    print(key.prettyPrint())
+    print((key.prettyPrint()))
 
     assert encoder.encode(key, defMode=False) == substrate or \
            encoder.encode(key, defMode=True) == substrate, \
@@ -35,4 +36,4 @@ while 1:
         
     cnt = cnt + 1
  
-print('*** %s CRL(s) re/serialized' % cnt)
+print(('*** %s CRL(s) re/serialized' % cnt))
diff --git a/python/pyasn1-modules/tools/crmfdump.py b/python/pyasn1-modules/tools/crmfdump.py
index 22bfc9d950..764b897440 100755
--- a/python/pyasn1-modules/tools/crmfdump.py
+++ b/python/pyasn1-modules/tools/crmfdump.py
@@ -1,13 +1,14 @@
 #!/usr/bin/python
 # Read ASN.1/PEM X.509 CRMF request on stdin, parse into
 # plain text, then build substrate from it
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2511, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat crmf.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat crmf.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 certReq = rfc2511.CertReqMessages()
@@ -18,7 +19,7 @@ if not substrate:
         
 cr, rest = decoder.decode(substrate, asn1Spec=certReq)
 
-print(cr.prettyPrint())
+print((cr.prettyPrint()))
 
 assert encoder.encode(cr, defMode=False) == substrate or \
        encoder.encode(cr, defMode=True) == substrate, \
diff --git a/python/pyasn1-modules/tools/ocspclient.py b/python/pyasn1-modules/tools/ocspclient.py
index b2d1dfc54f..d125cbad0a 100755
--- a/python/pyasn1-modules/tools/ocspclient.py
+++ b/python/pyasn1-modules/tools/ocspclient.py
@@ -1,11 +1,12 @@
 #!/usr/bin/python
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2560, rfc2459, pem
 from pyasn1.type import univ
 import sys, hashlib
 try:
-  import urllib2
+  import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 except ImportError:
   import urllib.request as urllib2
 
@@ -33,7 +34,7 @@ def mkOcspRequest(issuerCert, userCert):
     userTbsCertificate = userCert.getComponentByName('tbsCertificate')
     userIssuer = userTbsCertificate.getComponentByName('issuer')
 
-    assert issuerSubject == userIssuer, '%s\n%s' % (
+    assert issuerSubject == userIssuer, '{}\n{}'.format(
         issuerSubject.prettyPrint(), userIssuer.prettyPrint()
         )
 
@@ -97,8 +98,8 @@ def parseOcspResponse(ocspResponse):
         )
 
 if len(sys.argv) != 2:
-    print("""Usage:
-$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0])
+    print(("""Usage:
+$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0]))
     sys.exit(-1)
 else:
     ocspUrl = sys.argv[1]
@@ -125,12 +126,12 @@ ocspReq = mkOcspRequest(issuerCert, userCert)
 # Use HTTP POST to get response (see Appendix A of RFC 2560)
 # In case you need proxies, set the http_proxy env variable
 
-httpReq = urllib2.Request(
+httpReq = six.moves.urllib.request.Request(
     ocspUrl,
     encoder.encode(ocspReq),
     { 'Content-Type': 'application/ocsp-request' }
     )
-httpRsp = urllib2.urlopen(httpReq).read()
+httpRsp = six.moves.urllib.request.urlopen(httpReq).read()
 
 # Process OCSP response
     
@@ -138,8 +139,8 @@ ocspRsp, _ = decoder.decode(httpRsp, asn1Spec=rfc2560.OCSPResponse())
 
 producedAt, certId, certStatus, thisUpdate = parseOcspResponse(ocspRsp)
 
-print('Certificate ID %s is %s at %s till %s\n' % (
+print(('Certificate ID {} is {} at {} till {}\n'.format(
        certId.getComponentByName('serialNumber'),
        certStatus,
        producedAt,
-       thisUpdate))
+       thisUpdate)))
diff --git a/python/pyasn1-modules/tools/ocspreqdump.py b/python/pyasn1-modules/tools/ocspreqdump.py
index 3a03115ea4..a7e19ae86a 100755
--- a/python/pyasn1-modules/tools/ocspreqdump.py
+++ b/python/pyasn1-modules/tools/ocspreqdump.py
@@ -3,13 +3,14 @@
 # Read ASN.1/PEM X.509 CRMF request on stdin, parse into
 # plain text, then build substrate from it
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2560, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat ocsp-request.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat ocsp-request.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 ocspReq = rfc2560.OCSPRequest()
@@ -20,7 +21,7 @@ if not substrate:
         
 cr, rest = decoder.decode(substrate, asn1Spec=ocspReq)
 
-print(cr.prettyPrint())
+print((cr.prettyPrint()))
 
 assert encoder.encode(cr, defMode=False) == substrate or \
        encoder.encode(cr, defMode=True) == substrate, \
diff --git a/python/pyasn1-modules/tools/ocsprspdump.py b/python/pyasn1-modules/tools/ocsprspdump.py
index 9e49ce038d..562d563705 100755
--- a/python/pyasn1-modules/tools/ocsprspdump.py
+++ b/python/pyasn1-modules/tools/ocsprspdump.py
@@ -3,13 +3,14 @@
 # Read ASN.1/PEM OCSP response on stdin, parse into
 # plain text, then build substrate from it
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2560, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat ocsp-response.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat ocsp-response.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 ocspReq = rfc2560.OCSPResponse()
@@ -20,7 +21,7 @@ if not substrate:
         
 cr, rest = decoder.decode(substrate, asn1Spec=ocspReq)
 
-print(cr.prettyPrint())
+print((cr.prettyPrint()))
 
 assert encoder.encode(cr, defMode=False) == substrate or \
        encoder.encode(cr, defMode=True) == substrate, \
diff --git a/python/pyasn1-modules/tools/ocspserver.py b/python/pyasn1-modules/tools/ocspserver.py
index 2d12d53998..e862720f67 100755
--- a/python/pyasn1-modules/tools/ocspserver.py
+++ b/python/pyasn1-modules/tools/ocspserver.py
@@ -1,11 +1,12 @@
 #!/usr/bin/python
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2560, rfc2459, pem
 from pyasn1.type import univ
 import sys, hashlib
 try:
-    import urllib2
+    import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 except ImportError:
     import urllib.request as urllib2
 
@@ -33,7 +34,7 @@ def mkOcspRequest(issuerCert, userCert):
     userTbsCertificate = userCert.getComponentByName('tbsCertificate')
     userIssuer = userTbsCertificate.getComponentByName('issuer')
 
-    assert issuerSubject == userIssuer, '%s\n%s' % (
+    assert issuerSubject == userIssuer, '{}\n{}'.format(
         issuerSubject.prettyPrint(), userIssuer.prettyPrint()
         )
 
@@ -98,8 +99,8 @@ def parseOcspRequest(ocspRequest):
         )
 
 if len(sys.argv) != 2:
-    print("""Usage:
-$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0])
+    print(("""Usage:
+$ cat CACertificate.pem userCertificate.pem | %s <ocsp-responder-url>""" % sys.argv[0]))
     sys.exit(-1)
 else:
     ocspUrl = sys.argv[1]
@@ -122,12 +123,12 @@ ocspReq = mkOcspRequest(issuerCert, userCert)
 # Use HTTP POST to get response (see Appendix A of RFC 2560)
 # In case you need proxies, set the http_proxy env variable
 
-httpReq = urllib2.Request(
+httpReq = six.moves.urllib.request.Request(
     ocspUrl,
     encoder.encode(ocspReq),
     { 'Content-Type': 'application/ocsp-request' }
     )
-httpRsp = urllib2.urlopen(httpReq).read()
+httpRsp = six.moves.urllib.request.urlopen(httpReq).read()
 
 # Process OCSP response
     
@@ -135,9 +136,9 @@ ocspRsp, _ = decoder.decode(httpRsp, asn1Spec=rfc2560.OCSPResponse())
 
 producedAt, certId, certStatus, thisUpdate = parseOcspResponse(ocspRsp)
 
-print('Certificate ID %s is %s at %s till %s\n' % (
+print(('Certificate ID {} is {} at {} till {}\n'.format(
     certId.getComponentByName('serialNumber'),
     certStatus,
     producedAt,
     thisUpdate
-    ))
+    )))
diff --git a/python/pyasn1-modules/tools/pkcs10dump.py b/python/pyasn1-modules/tools/pkcs10dump.py
index ea979c0cf5..976d5c0e76 100755
--- a/python/pyasn1-modules/tools/pkcs10dump.py
+++ b/python/pyasn1-modules/tools/pkcs10dump.py
@@ -3,13 +3,14 @@
 # Read ASN.1/PEM X.509 certificate requests (PKCS#10 format) on stdin, 
 # parse each into plain text, then build substrate from it
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2314, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat certificateRequest.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat certificateRequest.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 certType = rfc2314.CertificationRequest()
@@ -28,7 +29,7 @@ while 1:
 
     if rest: substrate = substrate[:-len(rest)]
         
-    print(cert.prettyPrint())
+    print((cert.prettyPrint()))
 
     assert encoder.encode(cert, defMode=False) == substrate or \
            encoder.encode(cert, defMode=True) == substrate, \
@@ -36,4 +37,4 @@ while 1:
         
     certCnt = certCnt + 1
     
-print('*** %s PEM certificate request(s) de/serialized' % certCnt)
+print(('*** %s PEM certificate request(s) de/serialized' % certCnt))
diff --git a/python/pyasn1-modules/tools/pkcs1dump.py b/python/pyasn1-modules/tools/pkcs1dump.py
index d0da82b2fb..ff350c1076 100755
--- a/python/pyasn1-modules/tools/pkcs1dump.py
+++ b/python/pyasn1-modules/tools/pkcs1dump.py
@@ -4,13 +4,14 @@
 # stdin, print them pretty and encode back into original wire format.
 # Private keys can be generated with "openssl genrsa|gendsa" commands.
 #
+from __future__ import print_function
 from pyasn1_modules import rfc2459, rfc2437, pem
 from pyasn1.codec.der import encoder, decoder
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat rsakey.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat rsakey.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 cnt = 0
@@ -31,7 +32,7 @@ while 1:
 
     if rest: substrate = substrate[:-len(rest)]
         
-    print(key.prettyPrint())
+    print((key.prettyPrint()))
 
     assert encoder.encode(key, defMode=False) == substrate or \
            encoder.encode(key, defMode=True) == substrate, \
@@ -39,4 +40,4 @@ while 1:
         
     cnt = cnt + 1
  
-print('*** %s key(s) re/serialized' % cnt)
+print(('*** %s key(s) re/serialized' % cnt))
diff --git a/python/pyasn1-modules/tools/pkcs7dump.py b/python/pyasn1-modules/tools/pkcs7dump.py
index 7794871620..e47ba940c3 100755
--- a/python/pyasn1-modules/tools/pkcs7dump.py
+++ b/python/pyasn1-modules/tools/pkcs7dump.py
@@ -3,13 +3,14 @@
 # Read ASN.1/PEM PKCS#7 on stdin, parse it into plain text,
 # then build substrate from it
 #
+from __future__ import print_function
 from pyasn1_modules import rfc2315, pem
 from pyasn1.codec.der import encoder, decoder
 import sys
     
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat pkcs7Certificate.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat pkcs7Certificate.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 idx, substrate = pem.readPemBlocksFromFile(
@@ -22,7 +23,7 @@ contentInfo, rest = decoder.decode(substrate, asn1Spec=rfc2315.ContentInfo())
 
 if rest: substrate = substrate[:-len(rest)]
     
-print(contentInfo.prettyPrint())
+print((contentInfo.prettyPrint()))
 
 assert encoder.encode(contentInfo, defMode=False) == substrate or \
        encoder.encode(contentInfo, defMode=True) == substrate, \
@@ -44,4 +45,4 @@ content, _ = decoder.decode(
     asn1Spec=contentInfoMap[contentType]
     )
 
-print(content.prettyPrint())
+print((content.prettyPrint()))
diff --git a/python/pyasn1-modules/tools/pkcs8dump.py b/python/pyasn1-modules/tools/pkcs8dump.py
index d1d125f8cc..fa82a57d45 100755
--- a/python/pyasn1-modules/tools/pkcs8dump.py
+++ b/python/pyasn1-modules/tools/pkcs8dump.py
@@ -3,13 +3,14 @@
 # Read  bunch of ASN.1/PEM plain/encrypted private keys in PKCS#8 
 # format on stdin, parse each into plain text, then build substrate from it
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc5208, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat pkcs8key.pem | %s""" % sys.argv[0])
+    print(("""Usage:
+$ cat pkcs8key.pem | %s""" % sys.argv[0]))
     sys.exit(-1)
     
 cnt = 0
@@ -30,7 +31,7 @@ while 1:
 
     if rest: substrate = substrate[:-len(rest)]
         
-    print(key.prettyPrint())
+    print((key.prettyPrint()))
 
     assert encoder.encode(key, defMode=False) == substrate or \
            encoder.encode(key, defMode=True) == substrate, \
@@ -38,4 +39,4 @@ while 1:
         
     cnt = cnt + 1
     
-print('*** %s PKCS#8 key(s) de/serialized' % cnt)
+print(('*** %s PKCS#8 key(s) de/serialized' % cnt))
diff --git a/python/pyasn1-modules/tools/snmpget.py b/python/pyasn1-modules/tools/snmpget.py
index 372510329b..394bfd4eff 100755
--- a/python/pyasn1-modules/tools/snmpget.py
+++ b/python/pyasn1-modules/tools/snmpget.py
@@ -2,13 +2,14 @@
 #
 # Generate SNMPGET request, parse response
 #
+from __future__ import print_function
 from pyasn1.codec.ber import encoder, decoder
 from pyasn1_modules import rfc1157
 import sys, socket
 
 if len(sys.argv) != 4:
-    print("""Usage:
-$ %s <community> <host> <OID>""" % sys.argv[0])
+    print(("""Usage:
+$ %s <community> <host> <OID>""" % sys.argv[0]))
     sys.exit(-1)
 
 msg = rfc1157.Message()
@@ -25,7 +26,7 @@ vb = vbl.setComponentByPosition(0).getComponentByPosition(0)
 vb.setComponentByPosition(0, sys.argv[3])
 v = vb.setComponentByPosition(1).getComponentByPosition(1).setComponentByPosition(0).getComponentByPosition(0).setComponentByPosition(3).getComponentByPosition(3)
 
-print('sending: %s' % msg.prettyPrint())
+print(('sending: %s' % msg.prettyPrint()))
 
 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 sock.sendto(encoder.encode(msg), (sys.argv[2], 161))
@@ -34,4 +35,4 @@ substrate, _ = sock.recvfrom(2048)
 
 rMsg, _ = decoder.decode(substrate, asn1Spec=msg)
 
-print('received: %s' % rMsg.prettyPrint())
+print(('received: %s' % rMsg.prettyPrint()))
diff --git a/python/pyasn1-modules/tools/x509dump.py b/python/pyasn1-modules/tools/x509dump.py
index 64cba7e305..d95206fa74 100755
--- a/python/pyasn1-modules/tools/x509dump.py
+++ b/python/pyasn1-modules/tools/x509dump.py
@@ -3,14 +3,15 @@
 # Read ASN.1/PEM X.509 certificates on stdin, parse each into plain text,
 # then build substrate from it
 #
+from __future__ import print_function
 from pyasn1.codec.der import decoder, encoder
 from pyasn1_modules import rfc2459, pem
 import sys
 
 if len(sys.argv) != 1:
-    print("""Usage:
-$ cat CACertificate.pem | %s
-$ cat userCertificate.pem | %s""" % (sys.argv[0], sys.argv[0]))
+    print(("""Usage:
+$ cat CACertificate.pem | {}
+$ cat userCertificate.pem | {}""".format(sys.argv[0], sys.argv[0])))
     sys.exit(-1)
     
 certType = rfc2459.Certificate()
@@ -29,7 +30,7 @@ while 1:
 
     if rest: substrate = substrate[:-len(rest)]
         
-    print(cert.prettyPrint())
+    print((cert.prettyPrint()))
 
     assert encoder.encode(cert, defMode=False) == substrate or \
            encoder.encode(cert, defMode=True) == substrate, \
@@ -37,4 +38,4 @@ while 1:
         
     certCnt = certCnt + 1
     
-print('*** %s PEM cert(s) de/serialized' % certCnt)
+print(('*** %s PEM cert(s) de/serialized' % certCnt))
diff --git a/python/pyasn1/pyasn1/codec/ber/decoder.py b/python/pyasn1/pyasn1/codec/ber/decoder.py
index be0cf49074..abddc95dee 100644
--- a/python/pyasn1/pyasn1/codec/ber/decoder.py
+++ b/python/pyasn1/pyasn1/codec/ber/decoder.py
@@ -8,17 +8,17 @@ class AbstractDecoder:
     protoComponent = None
     def valueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
                      length, state, decodeFun, substrateFun):
-        raise error.PyAsn1Error('Decoder not implemented for %s' % (tagSet,))
+        raise error.PyAsn1Error('Decoder not implemented for {}'.format(tagSet))
 
     def indefLenValueDecoder(self, fullSubstrate, substrate, asn1Spec, tagSet,
                      length, state, decodeFun, substrateFun):
-        raise error.PyAsn1Error('Indefinite length mode decoder not implemented for %s' % (tagSet,))
+        raise error.PyAsn1Error('Indefinite length mode decoder not implemented for {}'.format(tagSet))
 
 class AbstractSimpleDecoder(AbstractDecoder):
     tagFormats = (tag.tagFormatSimple,)
     def _createComponent(self, asn1Spec, tagSet, value=None):
         if tagSet[0][1] not in self.tagFormats:
-            raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,))
+            raise error.PyAsn1Error('Invalid tag format {!r} for {!r}'.format(tagSet[0], self.protoComponent))
         if asn1Spec is None:
             return self.protoComponent.clone(value, tagSet)
         elif value is None:
@@ -30,7 +30,7 @@ class AbstractConstructedDecoder(AbstractDecoder):
     tagFormats = (tag.tagFormatConstructed,)
     def _createComponent(self, asn1Spec, tagSet, value=None):
         if tagSet[0][1] not in self.tagFormats:
-            raise error.PyAsn1Error('Invalid tag format %r for %r' % (tagSet[0], self.protoComponent,))
+            raise error.PyAsn1Error('Invalid tag format {!r} for {!r}'.format(tagSet[0], self.protoComponent))
         if asn1Spec is None:
             return self.protoComponent.clone(tagSet)
         else:
@@ -238,7 +238,7 @@ class ObjectIdentifierDecoder(AbstractSimpleDecoder):
                     subId = (subId << 7) + (nextSubId & 0x7F)
                     if index >= substrateLen:
                         raise error.SubstrateUnderrunError(
-                            'Short substrate for sub-OID past %s' % (oid,)
+                            'Short substrate for sub-OID past {}'.format(oid)
                             )
                     nextSubId = oct2int(head[index])
                     index = index + 1
@@ -568,7 +568,7 @@ typeMap = {
 
 ( stDecodeTag, stDecodeLength, stGetValueDecoder, stGetValueDecoderByAsn1Spec,
   stGetValueDecoderByTag, stTryAsExplicitTag, stDecodeValue,
-  stDumpRawValue, stErrorCondition, stStop ) = [x for x in range(10)]
+  stDumpRawValue, stErrorCondition, stStop ) = (x for x in range(10))
 
 class Decoder:
     defaultErrorState = stErrorCondition
@@ -711,7 +711,7 @@ class Decoder:
                     else:
                         state = stTryAsExplicitTag
                 if debug.logger and debug.logger & debug.flagDecoder:
-                    debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
+                    debug.logger('codec {} chosen by a built-in type, decoding {}'.format(concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
                     debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__)
             if state == stGetValueDecoderByAsn1Spec:
                 if isinstance(asn1Spec, (dict, tagmap.TagMap)):
@@ -722,12 +722,12 @@ class Decoder:
                     if debug.logger and debug.logger & debug.flagDecoder:
                         debug.logger('candidate ASN.1 spec is a map of:')
                         for t, v in asn1Spec.getPosMap().items():
-                            debug.logger('  %r -> %s' % (t, v.__class__.__name__))
+                            debug.logger('  {!r} -> {}'.format(t, v.__class__.__name__))
                         if asn1Spec.getNegMap():
                             debug.logger('but neither of: ')
                             for i in asn1Spec.getNegMap().items():
-                                debug.logger('  %r -> %s' % (t, v.__class__.__name__))
-                        debug.logger('new candidate ASN.1 spec is %s, chosen by %r' % (__chosenSpec is None and '<none>' or __chosenSpec.__class__.__name__, tagSet))
+                                debug.logger('  {!r} -> {}'.format(t, v.__class__.__name__))
+                        debug.logger('new candidate ASN.1 spec is {}, chosen by {!r}'.format(__chosenSpec is None and '<none>' or __chosenSpec.__class__.__name__, tagSet))
                 else:
                     __chosenSpec = asn1Spec
                     debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__)
@@ -741,11 +741,11 @@ class Decoder:
                            __chosenSpec.typeId in self.__typeMap:
                         # ambiguous type
                         concreteDecoder = self.__typeMap[__chosenSpec.typeId]
-                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,))
+                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID {}'.format(__chosenSpec.typeId))
                     elif baseTagSet in self.__tagMap:
                         # base type or tagged subtype
                         concreteDecoder = self.__tagMap[baseTagSet]
-                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %r' % (baseTagSet,))
+                        debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base {!r}'.format(baseTagSet))
                     else:
                         concreteDecoder = None
                     if concreteDecoder:
@@ -761,7 +761,7 @@ class Decoder:
                     concreteDecoder = None
                     state = stTryAsExplicitTag
                 if debug.logger and debug.logger & debug.flagDecoder:
-                    debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
+                    debug.logger('codec {} chosen by ASN.1 spec, decoding {}'.format(state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag'))
                     debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__)
             if state == stTryAsExplicitTag:
                 if tagSet and \
@@ -773,7 +773,7 @@ class Decoder:
                 else:                    
                     concreteDecoder = None
                     state = self.defaultErrorState
-                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure'))
+                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec {} chosen, decoding {}'.format(concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure'))
             if state == stDumpRawValue:
                 concreteDecoder = self.defaultRawDecoder
                 debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__)
@@ -792,10 +792,10 @@ class Decoder:
                         stGetValueDecoder, self, substrateFun
                         )
                 state = stStop
-                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>'))
+                debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec {} yields type {}, value:\n{}\n...remaining substrate is: {}'.format(concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>'))
             if state == stErrorCondition:
                 raise error.PyAsn1Error(
-                    '%r not in asn1Spec: %r' % (tagSet, asn1Spec)
+                    '{!r} not in asn1Spec: {!r}'.format(tagSet, asn1Spec)
                     )
         if debug.logger and debug.logger & debug.flagDecoder:
             debug.scope.pop()
diff --git a/python/pyasn1/pyasn1/codec/ber/encoder.py b/python/pyasn1/pyasn1/codec/ber/encoder.py
index 173949d0b6..7e5c7129a4 100644
--- a/python/pyasn1/pyasn1/codec/ber/encoder.py
+++ b/python/pyasn1/pyasn1/codec/ber/encoder.py
@@ -164,12 +164,12 @@ class ObjectIdentifierEncoder(AbstractItemEncoder):
             index = 5
         else:
             if len(oid) < 2:
-                raise error.PyAsn1Error('Short OID %s' % (value,))
+                raise error.PyAsn1Error('Short OID {}'.format(value))
 
             # Build the first twos
             if oid[0] > 6 or oid[1] > 39 or oid[0] == 6 and oid[1] > 15:
                 raise error.PyAsn1Error(
-                    'Initial sub-ID overflow %s in OID %s' % (oid[:2], value)
+                    'Initial sub-ID overflow {} in OID {}'.format(oid[:2], value)
                     )
             octets = (oid[0] * 40 + oid[1],)
             index = 2
@@ -181,7 +181,7 @@ class ObjectIdentifierEncoder(AbstractItemEncoder):
                 octets = octets + (subid & 0x7f,)
             elif subid < 0 or subid > 0xFFFFFFFF:
                 raise error.PyAsn1Error(
-                    'SubId overflow %s in %s' % (subid, value)
+                    'SubId overflow {} in {}'.format(subid, value)
                     )
             else:
                 # Pack large Sub-Object IDs
@@ -328,7 +328,7 @@ class Encoder:
         self.__typeMap = typeMap
 
     def __call__(self, value, defMode=1, maxChunkSize=0):
-        debug.logger & debug.flagEncoder and debug.logger('encoder called in %sdef mode, chunk size %s for type %s, value:\n%s' % (not defMode and 'in' or '', maxChunkSize, value.__class__.__name__, value.prettyPrint()))
+        debug.logger & debug.flagEncoder and debug.logger('encoder called in {}def mode, chunk size {} for type {}, value:\n{}'.format(not defMode and 'in' or '', maxChunkSize, value.__class__.__name__, value.prettyPrint()))
         tagSet = value.getTagSet()
         if len(tagSet) > 1:
             concreteEncoder = explicitlyTaggedItemEncoder
@@ -342,12 +342,12 @@ class Encoder:
                 if tagSet in self.__tagMap:
                     concreteEncoder = self.__tagMap[tagSet]
                 else:
-                    raise Error('No encoder for %s' % (value,))
-        debug.logger & debug.flagEncoder and debug.logger('using value codec %s chosen by %r' % (concreteEncoder.__class__.__name__, tagSet))
+                    raise Error('No encoder for {}'.format(value))
+        debug.logger & debug.flagEncoder and debug.logger('using value codec {} chosen by {!r}'.format(concreteEncoder.__class__.__name__, tagSet))
         substrate = concreteEncoder.encode(
             self, value, defMode, maxChunkSize
             )
-        debug.logger & debug.flagEncoder and debug.logger('built %s octets of substrate: %s\nencoder completed' % (len(substrate), debug.hexdump(substrate)))
+        debug.logger & debug.flagEncoder and debug.logger('built {} octets of substrate: {}\nencoder completed'.format(len(substrate), debug.hexdump(substrate)))
         return substrate
 
 encode = Encoder(tagMap, typeMap)
diff --git a/python/pyasn1/pyasn1/debug.py b/python/pyasn1/pyasn1/debug.py
index c27cb1d446..080fb1700d 100644
--- a/python/pyasn1/pyasn1/debug.py
+++ b/python/pyasn1/pyasn1/debug.py
@@ -22,12 +22,12 @@ class Debug:
         self('running pyasn1 version %s' % __version__)
         for f in flags:
             if f not in flagMap:
-                raise error.PyAsn1Error('bad debug flag %s' % (f,))
+                raise error.PyAsn1Error('bad debug flag {}'.format(f))
             self._flags = self._flags | flagMap[f]
             self('debug category \'%s\' enabled' % f)
         
     def __str__(self):
-        return 'logger %s, flags %x' % (self._printer, self._flags)
+        return 'logger {}, flags {:x}'.format(self._printer, self._flags)
     
     def __call__(self, msg):
         self._printer('DBG: %s\n' % msg)
@@ -46,8 +46,8 @@ def setLogger(l):
 
 def hexdump(octets):
     return ' '.join(
-            [ '%s%.2X' % (n%16 == 0 and ('\n%.5d: ' % n) or '', x) 
-              for n,x in zip(range(len(octets)), octs2ints(octets)) ]
+            [ '{}{:.2X}'.format(n%16 == 0 and ('\n%.5d: ' % n) or '', x) 
+              for n,x in zip(list(range(len(octets))), octs2ints(octets)) ]
         )
 
 class Scope:
diff --git a/python/pyasn1/pyasn1/type/base.py b/python/pyasn1/pyasn1/type/base.py
index 40873719ca..9391b85eb6 100644
--- a/python/pyasn1/pyasn1/type/base.py
+++ b/python/pyasn1/pyasn1/type/base.py
@@ -30,7 +30,7 @@ class Asn1ItemBase(Asn1Item):
             self._subtypeSpec(value, idx)
         except error.PyAsn1Error:
             c, i, t = sys.exc_info()
-            raise c('%s at %s' % (i, self.__class__.__name__))
+            raise c('{} at {}'.format(i, self.__class__.__name__))
         
     def getSubtypeSpec(self): return self._subtypeSpec
     
@@ -75,7 +75,7 @@ class AbstractSimpleAsn1Item(Asn1ItemBase):
         if self._value is noValue:
             return self.__class__.__name__ + '()'
         else:
-            return self.__class__.__name__ + '(%s)' % (self.prettyOut(self._value),)
+            return self.__class__.__name__ + '({})'.format(self.prettyOut(self._value))
     def __str__(self): return str(self._value)
     def __eq__(self, other):
         return self is other and True or self._value == other
@@ -170,7 +170,7 @@ class AbstractConstructedAsn1Item(Asn1ItemBase):
         for idx in range(len(self._componentValues)):
             if self._componentValues[idx] is None:
                 continue
-            r = r + '.setComponentByPosition(%s, %r)' % (
+            r = r + '.setComponentByPosition({}, {!r})'.format(
                 idx, self._componentValues[idx]
                 )
         return r
diff --git a/python/pyasn1/pyasn1/type/constraint.py b/python/pyasn1/pyasn1/type/constraint.py
index 66873937d8..a02c37eaf9 100644
--- a/python/pyasn1/pyasn1/type/constraint.py
+++ b/python/pyasn1/pyasn1/type/constraint.py
@@ -29,10 +29,10 @@ class AbstractConstraint:
             self._testValue(value, idx)
         except error.ValueConstraintError:
             raise error.ValueConstraintError(
-               '%s failed at: \"%s\"' % (self, sys.exc_info()[1])
+               '{} failed at: \"{}\"'.format(self, sys.exc_info()[1])
             )
     def __repr__(self):
-        return '%s(%s)' % (
+        return '{}({})'.format(
             self.__class__.__name__,
             ', '.join([repr(x) for x in self._values])
         )
@@ -88,12 +88,12 @@ class ValueRangeConstraint(AbstractConstraint):
     def _setValues(self, values):
         if len(values) != 2:
             raise error.PyAsn1Error(
-                '%s: bad constraint values' % (self.__class__.__name__,)
+                '{}: bad constraint values'.format(self.__class__.__name__)
                 )
         self.start, self.stop = values
         if self.start > self.stop:
             raise error.PyAsn1Error(
-                '%s: screwed constraint values (start > stop): %s > %s' % (
+                '{}: screwed constraint values (start > stop): {} > {}'.format(
                     self.__class__.__name__,
                     self.start, self.stop
                 )
@@ -193,7 +193,7 @@ class ConstraintsUnion(AbstractConstraintSet):
             else:
                 return
         raise error.ValueConstraintError(
-            'all of %s failed for \"%s\"' % (self._values, value)
+            'all of {} failed for \"{}\"'.format(self._values, value)
             )
 
 # XXX
diff --git a/python/pyasn1/pyasn1/type/namedtype.py b/python/pyasn1/pyasn1/type/namedtype.py
index 48967a5fe2..b18ad30db5 100644
--- a/python/pyasn1/pyasn1/type/namedtype.py
+++ b/python/pyasn1/pyasn1/type/namedtype.py
@@ -8,7 +8,7 @@ class NamedType:
     isDefaulted = 0
     def __init__(self, name, t):
         self.__name = name; self.__type = t
-    def __repr__(self): return '%s(%s, %s)' % (
+    def __repr__(self): return '{}({}, {})'.format(
         self.__class__.__name__, self.__name, self.__type
         )
     def getType(self): return self.__type
@@ -35,7 +35,7 @@ class NamedTypes:
     def __repr__(self):
         r = '%s(' % self.__class__.__name__
         for n in self.__namedTypes:
-            r = r + '%r, ' % (n,)
+            r = r + '{!r}, '.format(n)
         return r + ')'
     
     def __getitem__(self, idx): return self.__namedTypes[idx]
@@ -60,12 +60,12 @@ class NamedTypes:
                 tagMap = self.__namedTypes[idx].getType().getTagMap()
                 for t in tagMap.getPosMap():
                     if t in self.__tagToPosIdx:
-                        raise error.PyAsn1Error('Duplicate type %s' % (t,))
+                        raise error.PyAsn1Error('Duplicate type {}'.format(t))
                     self.__tagToPosIdx[t] = idx
         try:
             return self.__tagToPosIdx[tagSet]
         except KeyError:
-            raise error.PyAsn1Error('Type %s not found' % (tagSet,))
+            raise error.PyAsn1Error('Type {} not found'.format(tagSet))
         
     def getNameByPosition(self, idx):
         try:
@@ -79,12 +79,12 @@ class NamedTypes:
                 idx = idx - 1
                 n = self.__namedTypes[idx].getName()
                 if n in self.__nameToPosIdx:
-                    raise error.PyAsn1Error('Duplicate name %s' % (n,))
+                    raise error.PyAsn1Error('Duplicate name {}'.format(n))
                 self.__nameToPosIdx[n] = idx
         try:
             return self.__nameToPosIdx[name]
         except KeyError:
-            raise error.PyAsn1Error('Name %s not found' % (name,))
+            raise error.PyAsn1Error('Name {} not found'.format(name))
 
     def __buildAmbigiousTagMap(self):
         ambigiousTypes = ()
diff --git a/python/pyasn1/pyasn1/type/namedval.py b/python/pyasn1/pyasn1/type/namedval.py
index d0fea7cc7c..26267eb1df 100644
--- a/python/pyasn1/pyasn1/type/namedval.py
+++ b/python/pyasn1/pyasn1/type/namedval.py
@@ -15,10 +15,10 @@ class NamedValues:
                 name = namedValue
                 val = automaticVal
             if name in self.nameToValIdx:
-                raise error.PyAsn1Error('Duplicate name %s' % (name,))
+                raise error.PyAsn1Error('Duplicate name {}'.format(name))
             self.nameToValIdx[name] = val
             if val in self.valToNameIdx:
-                raise error.PyAsn1Error('Duplicate value %s=%s' % (name, val))
+                raise error.PyAsn1Error('Duplicate value {}={}'.format(name, val))
             self.valToNameIdx[val] = name
             self.namedValues = self.namedValues + ((name, val),)
             automaticVal = automaticVal + 1
diff --git a/python/pyasn1/pyasn1/type/tag.py b/python/pyasn1/pyasn1/type/tag.py
index 1144907fa1..17122a59c3 100644
--- a/python/pyasn1/pyasn1/type/tag.py
+++ b/python/pyasn1/pyasn1/type/tag.py
@@ -18,7 +18,7 @@ class Tag:
     def __init__(self, tagClass, tagFormat, tagId):
         if tagId < 0:
             raise error.PyAsn1Error(
-                'Negative tag ID (%s) not allowed' % (tagId,)
+                'Negative tag ID ({}) not allowed'.format(tagId)
                 )
         self.__tag = (tagClass, tagFormat, tagId)
         self.uniq = (tagClass, tagId)
@@ -64,7 +64,7 @@ class TagSet:
         self.__lenOfSuperTags = len(superTags)
         
     def __repr__(self):
-        return '%s(%s)' % (
+        return '{}({})'.format(
             self.__class__.__name__,
             ', '.join([repr(x) for x in self.__superTags])
             )
diff --git a/python/pyasn1/pyasn1/type/tagmap.py b/python/pyasn1/pyasn1/type/tagmap.py
index 7cec3a10e4..5714487b49 100644
--- a/python/pyasn1/pyasn1/type/tagmap.py
+++ b/python/pyasn1/pyasn1/type/tagmap.py
@@ -21,14 +21,14 @@ class TagMap:
             raise KeyError()
 
     def __repr__(self):
-        s = '%r/%r' % (self.__posMap, self.__negMap)
+        s = '{!r}/{!r}'.format(self.__posMap, self.__negMap)
         if self.__defType is not None:
-            s = s + '/%r' % (self.__defType,)
+            s = s + '/{!r}'.format(self.__defType)
         return s
 
     def clone(self, parentType, tagMap, uniq=False):
         if self.__defType is not None and tagMap.getDef() is not None:
-            raise error.PyAsn1Error('Duplicate default value at %s' % (self,))
+            raise error.PyAsn1Error('Duplicate default value at {}'.format(self))
         if tagMap.getDef() is not None:
             defType = tagMap.getDef()
         else:
@@ -37,7 +37,7 @@ class TagMap:
         posMap = self.__posMap.copy()
         for k in tagMap.getPosMap():
             if uniq and k in posMap:
-                raise error.PyAsn1Error('Duplicate positive key %s' % (k,))
+                raise error.PyAsn1Error('Duplicate positive key {}'.format(k))
             posMap[k] = parentType
 
         negMap = self.__negMap.copy()
diff --git a/python/pyasn1/pyasn1/type/univ.py b/python/pyasn1/pyasn1/type/univ.py
index 9cd16f8a2a..12bdbad339 100644
--- a/python/pyasn1/pyasn1/type/univ.py
+++ b/python/pyasn1/pyasn1/type/univ.py
@@ -55,7 +55,7 @@ class Integer(base.AbstractSimpleAsn1Item):
 
     def __int__(self): return int(self._value)
     if sys.version_info[0] <= 2:
-        def __long__(self): return long(self._value)
+        def __long__(self): return int(self._value)
     def __float__(self): return float(self._value)    
     def __abs__(self): return abs(self._value)
     def __index__(self): return int(self._value)
@@ -73,7 +73,7 @@ class Integer(base.AbstractSimpleAsn1Item):
                 return int(value)
             except:
                 raise error.PyAsn1Error(
-                    'Can\'t coerce %s into integer: %s' % (value, sys.exc_info()[1])
+                    'Can\'t coerce {} into integer: {}'.format(value, sys.exc_info()[1])
                     )
         r = self.__namedValues.getValue(value)
         if r is not None:
@@ -82,7 +82,7 @@ class Integer(base.AbstractSimpleAsn1Item):
             return int(value)
         except:
             raise error.PyAsn1Error(
-                'Can\'t coerce %s into integer: %s' % (value, sys.exc_info()[1])
+                'Can\'t coerce {} into integer: {}'.format(value, sys.exc_info()[1])
                 )
 
     def prettyOut(self, value):
@@ -216,7 +216,7 @@ class BitString(base.AbstractSimpleAsn1Item):
                             r.append(1)
                         else:
                             raise error.PyAsn1Error(
-                                'Non-binary BIT STRING initializer %s' % (v,)
+                                'Non-binary BIT STRING initializer {}'.format(v)
                                 )
                     return tuple(r)
                 elif value[-2:] == '\'H':
@@ -229,14 +229,14 @@ class BitString(base.AbstractSimpleAsn1Item):
                     return tuple(r)
                 else:
                     raise error.PyAsn1Error(
-                        'Bad BIT STRING value notation %s' % (value,)
+                        'Bad BIT STRING value notation {}'.format(value)
                         )                
             else:
                 for i in value.split(','):
                     j = self.__namedValues.getValue(i)
                     if j is None:
                         raise error.PyAsn1Error(
-                            'Unknown bit identifier \'%s\'' % (i,)
+                            'Unknown bit identifier \'{}\''.format(i)
                             )
                     if j >= len(r):
                         r.extend([0]*(j-len(r)+1))
@@ -247,14 +247,14 @@ class BitString(base.AbstractSimpleAsn1Item):
             for b in r:
                 if b and b != 1:
                     raise error.PyAsn1Error(
-                        'Non-binary BitString initializer \'%s\'' % (r,)
+                        'Non-binary BitString initializer \'{}\''.format(r)
                         )
             return r
         elif isinstance(value, BitString):
             return tuple(value)
         else:
             raise error.PyAsn1Error(
-                'Bad BitString initializer type \'%s\'' % (value,)
+                'Bad BitString initializer type \'{}\''.format(value)
                 )
 
     def prettyOut(self, value):
@@ -309,7 +309,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
                     return ''.join([ chr(x) for x in value ])
                 except ValueError:
                     raise error.PyAsn1Error(
-                        'Bad OctetString initializer \'%s\'' % (value,)
+                        'Bad OctetString initializer \'{}\''.format(value)
                         )                
             else:
                 return str(value)
@@ -324,14 +324,14 @@ class OctetString(base.AbstractSimpleAsn1Item):
                     return bytes(value)
                 except ValueError:
                     raise error.PyAsn1Error(
-                        'Bad OctetString initializer \'%s\'' % (value,)
+                        'Bad OctetString initializer \'{}\''.format(value)
                         )
             else:
                 try:
                     return str(value).encode(self._encoding)
                 except UnicodeEncodeError:
                     raise error.PyAsn1Error(
-                        'Can\'t encode string \'%s\' with \'%s\' codec' % (value, self._encoding)
+                        'Can\'t encode string \'{}\' with \'{}\' codec'.format(value, self._encoding)
                         )
                         
 
@@ -350,7 +350,7 @@ class OctetString(base.AbstractSimpleAsn1Item):
                 v = 1
             else:
                 raise error.PyAsn1Error(
-                    'Non-binary OCTET STRING initializer %s' % (v,)
+                    'Non-binary OCTET STRING initializer {}'.format(v)
                     )
             byte = byte | (v << bitNo)
         return octets.ints2octs(r + (byte,))
@@ -421,14 +421,14 @@ class OctetString(base.AbstractSimpleAsn1Item):
     def __rmul__(self, value): return self * value
 
 class Null(OctetString):
-    defaultValue = ''.encode()  # This is tightly constrained
+    defaultValue = b''  # This is tightly constrained
     tagSet = baseTagSet = tag.initTagSet(
         tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 0x05)
         )
-    subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint(''.encode())
+    subtypeSpec = OctetString.subtypeSpec+constraint.SingleValueConstraint(b'')
     
 if sys.version_info[0] <= 2:
-    intTypes = (int, long)
+    intTypes = int
 else:
     intTypes = int
 
@@ -496,7 +496,7 @@ class ObjectIdentifier(base.AbstractSimpleAsn1Item):
         for x in value:
             if not isinstance(x, intTypes) or x < 0:
                 raise error.PyAsn1Error(
-                    'Invalid sub-ID in %s at %s' % (value, self.__class__.__name__)
+                    'Invalid sub-ID in {} at {}'.format(value, self.__class__.__name__)
                     )
     
         return value
@@ -529,11 +529,11 @@ class Real(base.AbstractSimpleAsn1Item):
             for d in value:
                 if not isinstance(d, intTypes):
                     raise error.PyAsn1Error(
-                        'Lame Real value syntax: %s' % (value,)
+                        'Lame Real value syntax: {}'.format(value)
                         )
             if value[1] not in (2, 10):
                 raise error.PyAsn1Error(
-                    'Prohibited base for Real value: %s' % (value[1],)
+                    'Prohibited base for Real value: {}'.format(value[1])
                     )
             if value[1] == 10:
                 value = self.__normalizeBase10(value)
@@ -557,7 +557,7 @@ class Real(base.AbstractSimpleAsn1Item):
             except ValueError:
                 pass
         raise error.PyAsn1Error(
-            'Bad real value syntax: %s' % (value,)
+            'Bad real value syntax: {}'.format(value)
             )
         
     def prettyOut(self, value):
@@ -594,7 +594,7 @@ class Real(base.AbstractSimpleAsn1Item):
 
     def __int__(self): return int(float(self))
     if sys.version_info[0] <= 2:
-        def __long__(self): return long(float(self))
+        def __long__(self): return int(float(self))
     def __float__(self):
         if self._value in self._inf:
             return self._value
@@ -653,7 +653,7 @@ class SetOf(base.AbstractConstructedAsn1Item):
     def _verifyComponent(self, idx, value):
         if self._componentType is not None and \
                not self._componentType.isSuperTypeOf(value):
-            raise error.PyAsn1Error('Component type error %s' % (value,))
+            raise error.PyAsn1Error('Component type error {}'.format(value))
 
     def getComponentByPosition(self, idx): return self._componentValues[idx]
     def setComponentByPosition(self, idx, value=None, verifyConstraints=True):
@@ -748,7 +748,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
                 )
         t = self._componentType[idx].getType()
         if not t.isSuperTypeOf(value):
-            raise error.PyAsn1Error('Component type error %r vs %r' % (t, value))
+            raise error.PyAsn1Error('Component type error {!r} vs {!r}'.format(t, value))
 
     def getComponentByName(self, name):
         return self.getComponentByPosition(
@@ -815,7 +815,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
             elif not self._componentType[idx].isOptional:
                 if self.getComponentByPosition(idx) is None:
                     raise error.PyAsn1Error(
-                        'Uninitialized component #%s at %r' % (idx, self)
+                        'Uninitialized component #{} at {!r}'.format(idx, self)
                         )
 
     def prettyPrint(self, scope=0):
@@ -829,7 +829,7 @@ class SequenceAndSetBase(base.AbstractConstructedAsn1Item):
                     r = r + '<no-name>'
                 else:
                     r = r + componentType.getNameByPosition(idx)
-                r = '%s=%s\n' % (
+                r = '{}={}\n'.format(
                     r, self._componentValues[idx].prettyPrint(scope)
                     )
         return r
diff --git a/python/pyasn1/setup.py b/python/pyasn1/setup.py
index 194f0c8ca8..9637798bc4 100644
--- a/python/pyasn1/setup.py
+++ b/python/pyasn1/setup.py
@@ -4,6 +4,7 @@
    A pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208).
 """
 
+from __future__ import print_function
 import os
 import sys
 
diff --git a/python/pyasn1/test/codec/ber/suite.py b/python/pyasn1/test/codec/ber/suite.py
index 796c526b4b..4227dc1cfb 100644
--- a/python/pyasn1/test/codec/ber/suite.py
+++ b/python/pyasn1/test/codec/ber/suite.py
@@ -1,7 +1,7 @@
 from sys import path, version_info
 from os.path import sep
 path.insert(1, path[0]+sep+'ber')
-import test_encoder, test_decoder
+from . import test_encoder, test_decoder
 from pyasn1.error import PyAsn1Error
 if version_info[0:2] < (2, 7) or \
    version_info[0:2] in ( (3, 0), (3, 1) ):
diff --git a/python/pyasn1/test/codec/cer/suite.py b/python/pyasn1/test/codec/cer/suite.py
index 49d682918b..eecccbc5b5 100644
--- a/python/pyasn1/test/codec/cer/suite.py
+++ b/python/pyasn1/test/codec/cer/suite.py
@@ -1,7 +1,7 @@
 from sys import path, version_info
 from os.path import sep
 path.insert(1, path[0]+sep+'cer')
-import test_encoder, test_decoder
+from . import test_encoder, test_decoder
 from pyasn1.error import PyAsn1Error
 if version_info[0:2] < (2, 7) or \
    version_info[0:2] in ( (3, 0), (3, 1) ):
diff --git a/python/pyasn1/test/codec/der/suite.py b/python/pyasn1/test/codec/der/suite.py
index 7af83bf94f..7d73e3aa87 100644
--- a/python/pyasn1/test/codec/der/suite.py
+++ b/python/pyasn1/test/codec/der/suite.py
@@ -1,7 +1,7 @@
 from sys import path, version_info
 from os.path import sep
 path.insert(1, path[0]+sep+'der')
-import test_encoder, test_decoder
+from . import test_encoder, test_decoder
 from pyasn1.error import PyAsn1Error
 if version_info[0:2] < (2, 7) or \
    version_info[0:2] in ( (3, 0), (3, 1) ):
diff --git a/python/pyasn1/test/codec/der/test_decoder.py b/python/pyasn1/test/codec/der/test_decoder.py
index 5c9a1948b9..f2718d2115 100644
--- a/python/pyasn1/test/codec/der/test_decoder.py
+++ b/python/pyasn1/test/codec/der/test_decoder.py
@@ -14,7 +14,7 @@ else:
 class OctetStringDecoderTestCase(unittest.TestCase):
     def testShortMode(self):
         assert decoder.decode(
-            '\004\017Quick brown fox'.encode()
-            ) == ('Quick brown fox'.encode(), ''.encode())
+            b'\004\017Quick brown fox'
+            ) == (b'Quick brown fox', b'')
 
 if __name__ == '__main__': unittest.main()
diff --git a/python/pyasn1/test/codec/suite.py b/python/pyasn1/test/codec/suite.py
index 93ff063818..fe44b6bd50 100644
--- a/python/pyasn1/test/codec/suite.py
+++ b/python/pyasn1/test/codec/suite.py
@@ -1,11 +1,11 @@
 from sys import path, version_info
 from os.path import sep
 path.insert(1, path[0]+sep+'codec'+sep+'ber')
-import ber.suite
+from . import ber.suite
 path.insert(1, path[0]+sep+'codec'+sep+'cer')
-import cer.suite
+from . import cer.suite
 path.insert(1, path[0]+sep+'codec'+sep+'der')
-import der.suite
+from . import der.suite
 from pyasn1.error import PyAsn1Error
 if version_info[0:2] < (2, 7) or \
    version_info[0:2] in ( (3, 0), (3, 1) ):
diff --git a/python/pyasn1/test/suite.py b/python/pyasn1/test/suite.py
index b4d80e864a..11b121b2ce 100644
--- a/python/pyasn1/test/suite.py
+++ b/python/pyasn1/test/suite.py
@@ -1,9 +1,9 @@
 from sys import path, version_info
 from os.path import sep
 path.insert(1, path[0]+sep+'type')
-import type.suite
+from . import type.suite
 path.insert(1, path[0]+sep+'codec')
-import codec.suite
+from . import codec.suite
 from pyasn1.error import PyAsn1Error
 if version_info[0:2] < (2, 7) or \
    version_info[0:2] in ( (3, 0), (3, 1) ):
diff --git a/python/pyasn1/test/type/suite.py b/python/pyasn1/test/type/suite.py
index bc4b48685f..5dc46b0293 100644
--- a/python/pyasn1/test/type/suite.py
+++ b/python/pyasn1/test/type/suite.py
@@ -1,4 +1,4 @@
-import test_tag, test_constraint, test_namedtype, test_univ
+from . import test_tag, test_constraint, test_namedtype, test_univ
 from pyasn1.error import PyAsn1Error
 from sys import version_info
 if version_info[0:2] < (2, 7) or \
diff --git a/python/pylru/pylru.py b/python/pylru/pylru.py
index e69cadb76c..99efcdd406 100644
--- a/python/pylru/pylru.py
+++ b/python/pylru/pylru.py
@@ -1,4 +1,3 @@
-
 # Cache implementaion with a Least Recently Used (LRU) replacement policy and
 # a basic dictionary interface.
 
@@ -32,12 +31,12 @@
 # lookup of values by key.
 
 # Class for the node objects.
-class _dlnode(object):
+class _dlnode:
     def __init__(self):
         self.empty = True
 
 
-class lrucache(object):
+class lrucache:
 
     def __init__(self, size, callback=None):
 
@@ -287,7 +286,7 @@ class lrucache(object):
 
 
 
-class WriteThroughCacheManager(object):
+class WriteThroughCacheManager:
     def __init__(self, store, size):
         self.store = store
         self.cache = lrucache(size)
@@ -354,20 +353,20 @@ class WriteThroughCacheManager(object):
             pass
 
     def __iter__(self):
-        return self.keys()
+        return list(self.keys())
 
     def keys(self):
-        return self.store.keys()
+        return list(self.store.keys())
 
     def values(self):
-        return self.store.values()
+        return list(self.store.values())
 
     def items(self):
-        return self.store.items()
+        return list(self.store.items())
 
 
 
-class WriteBackCacheManager(object):
+class WriteBackCacheManager:
     def __init__(self, store, size):
         self.store = store
 
@@ -454,7 +453,7 @@ class WriteBackCacheManager(object):
 
 
     def __iter__(self):
-        return self.keys()
+        return list(self.keys())
 
     def keys(self):
         for key in self.store.keys():
@@ -501,7 +500,7 @@ class WriteBackCacheManager(object):
         return False
 
 
-class FunctionCacheManager(object):
+class FunctionCacheManager:
     def __init__(self, func, size):
         self.func = func
         self.cache = lrucache(size)
@@ -533,7 +532,7 @@ def lruwrap(store, size, writeback=False):
 
 import functools
 
-class lrudecorator(object):
+class lrudecorator:
     def __init__(self, size):
         self.cache = lrucache(size)
 
diff --git a/python/pylru/test.py b/python/pylru/test.py
index 7a4842fb52..67d170dc94 100644
--- a/python/pylru/test.py
+++ b/python/pylru/test.py
@@ -1,4 +1,3 @@
-
 from pylru import *
 import random
 
@@ -112,7 +111,7 @@ def testcache():
             q2.append((x, y))
 
         assert list(a.items()) == q2
-        assert list(zip(a.keys(), a.values())) == q2
+        assert list(zip(list(a.keys()), list(a.values()))) == q2
         assert list(a.keys()) == list(a)
 
 
diff --git a/python/pystache/pystache/__init__.py b/python/pystache/pystache/__init__.py
index 4cf24344e5..e04e99f330 100644
--- a/python/pystache/pystache/__init__.py
+++ b/python/pystache/pystache/__init__.py
@@ -1,4 +1,3 @@
-
 """
 TODO: add a docstring.
 
diff --git a/python/pystache/pystache/commands/render.py b/python/pystache/pystache/commands/render.py
index 1a9c309d52..c398a9f92c 100644
--- a/python/pystache/pystache/commands/render.py
+++ b/python/pystache/pystache/commands/render.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides command-line access to pystache.
 
@@ -8,6 +6,8 @@ Run this script using the -h option for command-line help.
 """
 
 
+from __future__ import print_function
+import six
 try:
     import json
 except:
@@ -22,7 +22,7 @@ except:
         from sys import exc_info
         ex_type, ex_value, tb = exc_info()
         new_ex = Exception("%s: %s" % (ex_type.__name__, ex_value))
-        raise new_ex.__class__, new_ex, tb
+        six.reraise(new_ex.__class__, new_ex, tb)
 
 # The optparse module is deprecated in Python 2.7 in favor of argparse.
 # However, argparse is not available in Python 2.6 and earlier.
@@ -88,7 +88,7 @@ def main(sys_argv=sys.argv):
         context = json.loads(context)
 
     rendered = renderer.render(template, context)
-    print rendered
+    print(rendered)
 
 
 if __name__=='__main__':
diff --git a/python/pystache/pystache/commands/test.py b/python/pystache/pystache/commands/test.py
index 0872453388..0f530e67ac 100644
--- a/python/pystache/pystache/commands/test.py
+++ b/python/pystache/pystache/commands/test.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides a command to test pystache (unit tests, doctests, etc).
 
diff --git a/python/pystache/pystache/common.py b/python/pystache/pystache/common.py
index fb266dd8b5..f2b2b477f0 100644
--- a/python/pystache/pystache/common.py
+++ b/python/pystache/pystache/common.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 Exposes functionality needed throughout the project.
 
@@ -13,9 +11,9 @@ def _get_string_types():
     #   and byte strings, and 2to3 seems to convert all of "str", "unicode",
     #   and "basestring" to Python 3's "str".
     if version_info < (3, ):
-         return basestring
+         return str
     # The latter evaluates to "bytes" in Python 3 -- even after conversion by 2to3.
-    return (unicode, type(u"a".encode('utf-8')))
+    return (str, type(b"a"))
 
 
 _STRING_TYPES = _get_string_types()
@@ -53,7 +51,7 @@ def read(path):
         f.close()
 
 
-class MissingTags(object):
+class MissingTags:
 
     """Contains the valid values for Renderer.missing_tags."""
 
diff --git a/python/pystache/pystache/context.py b/python/pystache/pystache/context.py
index 6715916092..3019146d98 100644
--- a/python/pystache/pystache/context.py
+++ b/python/pystache/pystache/context.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 Exposes a ContextStack class.
 
@@ -18,7 +16,7 @@ from pystache.common import PystacheError
 
 
 # This equals '__builtin__' in Python 2 and 'builtins' in Python 3.
-_BUILTIN_MODULE = type(0).__module__
+_BUILTIN_MODULE = int.__module__
 
 
 # We use this private global variable as a return value to represent a key
@@ -29,7 +27,7 @@ _BUILTIN_MODULE = type(0).__module__
 # TODO: eliminate the need for a private global variable, e.g. by using the
 #   preferred Python approach of "easier to ask for forgiveness than permission":
 #     http://docs.python.org/glossary.html#term-eafp
-class NotFound(object):
+class NotFound:
     pass
 _NOT_FOUND = NotFound()
 
@@ -88,10 +86,10 @@ class KeyNotFoundError(PystacheError):
         self.details = details
 
     def __str__(self):
-        return "Key %s not found: %s" % (repr(self.key), self.details)
+        return "Key {} not found: {}".format(repr(self.key), self.details)
 
 
-class ContextStack(object):
+class ContextStack:
 
     """
     Provides dictionary-like access to a stack of zero or more items.
@@ -140,7 +138,7 @@ class ContextStack(object):
         "ContextStack({'alpha': 'abc'}, {'numeric': 123})"
 
         """
-        return "%s%s" % (self.__class__.__name__, tuple(self._stack))
+        return "{}{}".format(self.__class__.__name__, tuple(self._stack))
 
     @staticmethod
     def create(*context, **kwargs):
diff --git a/python/pystache/pystache/defaults.py b/python/pystache/pystache/defaults.py
index bcfdf4cd3a..39c4c3b655 100644
--- a/python/pystache/pystache/defaults.py
+++ b/python/pystache/pystache/defaults.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides a central location for defining default behavior.
 
@@ -39,7 +37,7 @@ STRING_ENCODING = sys.getdefaultencoding()
 FILE_ENCODING = sys.getdefaultencoding()
 
 # The delimiters to start with when parsing.
-DELIMITERS = (u'{{', u'}}')
+DELIMITERS = ('{{', '}}')
 
 # How to handle missing tags when rendering a template.
 MISSING_TAGS = MissingTags.ignore
diff --git a/python/pystache/pystache/init.py b/python/pystache/pystache/init.py
index 38bb1f5a0e..72160475e3 100644
--- a/python/pystache/pystache/init.py
+++ b/python/pystache/pystache/init.py
@@ -1,5 +1,3 @@
-# encoding: utf-8
-
 """
 This module contains the initialization logic called by __init__.py.
 
diff --git a/python/pystache/pystache/loader.py b/python/pystache/pystache/loader.py
index d4a7e5310f..682d8511e1 100644
--- a/python/pystache/pystache/loader.py
+++ b/python/pystache/pystache/loader.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides a Loader class for locating and reading templates.
 
@@ -24,11 +22,11 @@ def _make_to_unicode():
         """
         if encoding is None:
             encoding = defaults.STRING_ENCODING
-        return unicode(s, encoding, defaults.DECODE_ERRORS)
+        return str(s, encoding, defaults.DECODE_ERRORS)
     return to_unicode
 
 
-class Loader(object):
+class Loader:
 
     """
     Loads the template associated to a name or user-defined object.
@@ -86,7 +84,7 @@ class Loader(object):
     def _make_locator(self):
         return Locator(extension=self.extension)
 
-    def unicode(self, s, encoding=None):
+    def str(self, s, encoding=None):
         """
         Convert a string to unicode using the given encoding, and return it.
 
@@ -104,8 +102,8 @@ class Loader(object):
             Defaults to None.
 
         """
-        if isinstance(s, unicode):
-            return unicode(s)
+        if isinstance(s, str):
+            return str(s)
 
         return self.to_unicode(s, encoding)
 
@@ -119,7 +117,7 @@ class Loader(object):
         if encoding is None:
             encoding = self.file_encoding
 
-        return self.unicode(b, encoding)
+        return self.str(b, encoding)
 
     def load_file(self, file_name):
         """
diff --git a/python/pystache/pystache/locator.py b/python/pystache/pystache/locator.py
index 30c5b01e01..a0df2887eb 100644
--- a/python/pystache/pystache/locator.py
+++ b/python/pystache/pystache/locator.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides a Locator class for finding template files.
 
@@ -13,7 +11,7 @@ from pystache.common import TemplateNotFoundError
 from pystache import defaults
 
 
-class Locator(object):
+class Locator:
 
     def __init__(self, extension=None):
         """
diff --git a/python/pystache/pystache/parsed.py b/python/pystache/pystache/parsed.py
index 372d96c666..3574dcbfa3 100644
--- a/python/pystache/pystache/parsed.py
+++ b/python/pystache/pystache/parsed.py
@@ -1,12 +1,10 @@
-# coding: utf-8
-
 """
 Exposes a class that represents a parsed (or compiled) template.
 
 """
 
 
-class ParsedTemplate(object):
+class ParsedTemplate:
 
     """
     Represents a parsed or compiled template.
@@ -41,10 +39,10 @@ class ParsedTemplate(object):
         """
         # We avoid use of the ternary operator for Python 2.4 support.
         def get_unicode(node):
-            if type(node) is unicode:
+            if type(node) is str:
                 return node
             return node.render(engine, context)
-        parts = map(get_unicode, self._parse_tree)
+        parts = list(map(get_unicode, self._parse_tree))
         s = ''.join(parts)
 
-        return unicode(s)
+        return str(s)
diff --git a/python/pystache/pystache/parser.py b/python/pystache/pystache/parser.py
index 9a4fba235b..6086db45b4 100644
--- a/python/pystache/pystache/parser.py
+++ b/python/pystache/pystache/parser.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 Exposes a parse() function to parse template strings.
 
@@ -11,8 +9,8 @@ from pystache import defaults
 from pystache.parsed import ParsedTemplate
 
 
-END_OF_LINE_CHARACTERS = [u'\r', u'\n']
-NON_BLANK_RE = re.compile(ur'^(.)', re.M)
+END_OF_LINE_CHARACTERS = ['\r', '\n']
+NON_BLANK_RE = re.compile(r'^(.)', re.M)
 
 
 # TODO: add some unit tests for this.
@@ -35,7 +33,7 @@ def parse(template, delimiters=None):
     ['Hey ', _SectionNode(key='who', index_begin=12, index_end=21, parsed=[_EscapeNode(key='name'), '!'])]
 
     """
-    if type(template) is not unicode:
+    if type(template) is not str:
         raise Exception("Template is not unicode: %s" % type(template))
     parser = _Parser(delimiters)
     return parser.parse(template)
@@ -94,7 +92,7 @@ class _CommentNode(object):
         return _format(self)
 
     def render(self, engine, context):
-        return u''
+        return ''
 
 
 class _ChangeNode(object):
@@ -106,7 +104,7 @@ class _ChangeNode(object):
         return _format(self)
 
     def render(self, engine, context):
-        return u''
+        return ''
 
 
 class _EscapeNode(object):
@@ -147,7 +145,7 @@ class _PartialNode(object):
     def render(self, engine, context):
         template = engine.resolve_partial(self.key)
         # Indent before rendering.
-        template = re.sub(NON_BLANK_RE, self.indent + ur'\1', template)
+        template = re.sub(NON_BLANK_RE, self.indent + r'\1', template)
 
         return engine.render(template, context)
 
@@ -168,7 +166,7 @@ class _InvertedNode(object):
         # Note that lambdas are considered truthy for inverted sections
         # per the spec.
         if data:
-            return u''
+            return ''
         return self.parsed_section.render(engine, context)
 
 
@@ -218,7 +216,7 @@ class _SectionNode(object):
             parts.append(self.parsed.render(engine, context))
             context.pop()
 
-        return unicode(''.join(parts))
+        return str(''.join(parts))
 
 
 class _Parser(object):
diff --git a/python/pystache/pystache/renderengine.py b/python/pystache/pystache/renderengine.py
index c797b1765a..926d81206d 100644
--- a/python/pystache/pystache/renderengine.py
+++ b/python/pystache/pystache/renderengine.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 Defines a class responsible for rendering logic.
 
@@ -19,7 +17,7 @@ def context_get(stack, name):
     return stack.get(name)
 
 
-class RenderEngine(object):
+class RenderEngine:
 
     """
     Provides a render() method.
@@ -160,7 +158,7 @@ class RenderEngine(object):
         if not is_string(val):
             # In case the template is an integer, for example.
             val = self.to_str(val)
-        if type(val) is not unicode:
+        if type(val) is not str:
             val = self.literal(val)
         return self.render(val, context, delimiters)
 
diff --git a/python/pystache/pystache/renderer.py b/python/pystache/pystache/renderer.py
index ff6a90c64b..3902a9e2bf 100644
--- a/python/pystache/pystache/renderer.py
+++ b/python/pystache/pystache/renderer.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module provides a Renderer class to render templates.
 
@@ -17,7 +15,7 @@ from pystache.specloader import SpecLoader
 from pystache.template_spec import TemplateSpec
 
 
-class Renderer(object):
+class Renderer:
 
     """
     A class for rendering mustache templates.
@@ -130,7 +128,7 @@ class Renderer(object):
         if string_encoding is None:
             string_encoding = defaults.STRING_ENCODING
 
-        if isinstance(search_dirs, basestring):
+        if isinstance(search_dirs, str):
             search_dirs = [search_dirs]
 
         self._context = None
@@ -177,16 +175,16 @@ class Renderer(object):
         """
         # We type-check to avoid "TypeError: decoding Unicode is not supported".
         # We avoid the Python ternary operator for Python 2.4 support.
-        if isinstance(s, unicode):
+        if isinstance(s, str):
             return s
-        return self.unicode(s)
+        return self.str(s)
 
     def _to_unicode_hard(self, s):
         """
         Convert a basestring to a string with type unicode (not subclass).
 
         """
-        return unicode(self._to_unicode_soft(s))
+        return str(self._to_unicode_soft(s))
 
     def _escape_to_unicode(self, s):
         """
@@ -195,9 +193,9 @@ class Renderer(object):
         Returns a unicode string (not subclass).
 
         """
-        return unicode(self.escape(self._to_unicode_soft(s)))
+        return str(self.escape(self._to_unicode_soft(s)))
 
-    def unicode(self, b, encoding=None):
+    def str(self, b, encoding=None):
         """
         Convert a byte string to unicode, using string_encoding and decode_errors.
 
@@ -222,7 +220,7 @@ class Renderer(object):
 
         # TODO: Wrap UnicodeDecodeErrors with a message about setting
         # the string_encoding and decode_errors attributes.
-        return unicode(b, encoding, self.decode_errors)
+        return str(b, encoding, self.decode_errors)
 
     def _make_loader(self):
         """
@@ -230,7 +228,7 @@ class Renderer(object):
 
         """
         return Loader(file_encoding=self.file_encoding, extension=self.file_extension,
-                      to_unicode=self.unicode, search_dirs=self.search_dirs)
+                      to_unicode=self.str, search_dirs=self.search_dirs)
 
     def _make_load_template(self):
         """
@@ -299,7 +297,7 @@ class Renderer(object):
             try:
                 return load_partial(name)
             except TemplateNotFoundError:
-                return u''
+                return ''
 
         return resolve_partial
 
@@ -316,7 +314,7 @@ class Renderer(object):
             try:
                 return context_get(stack, name)
             except KeyNotFoundError:
-                return u''
+                return ''
 
         return resolve_context
 
diff --git a/python/pystache/pystache/specloader.py b/python/pystache/pystache/specloader.py
index 3a77d4c528..a572e53460 100644
--- a/python/pystache/pystache/specloader.py
+++ b/python/pystache/pystache/specloader.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 This module supports customized (aka special or specified) template loading.
 
@@ -11,7 +9,7 @@ from pystache.loader import Loader
 
 
 # TODO: add test cases for this class.
-class SpecLoader(object):
+class SpecLoader:
 
     """
     Supports loading custom-specified templates (from TemplateSpec instances).
@@ -83,7 +81,7 @@ class SpecLoader(object):
 
         """
         if spec.template is not None:
-            return self.loader.unicode(spec.template, spec.template_encoding)
+            return self.loader.str(spec.template, spec.template_encoding)
 
         path = self._find(spec)
 
diff --git a/python/pystache/pystache/template_spec.py b/python/pystache/pystache/template_spec.py
index 9e9f454c19..f287961aac 100644
--- a/python/pystache/pystache/template_spec.py
+++ b/python/pystache/pystache/template_spec.py
@@ -1,5 +1,3 @@
-# coding: utf-8
-
 """
 Provides a class to customize template information on a per-view basis.
 
@@ -9,7 +7,7 @@ stands for "special" or "specified" template information.
 
 """
 
-class TemplateSpec(object):
+class TemplateSpec:
 
     """
     A mixin or interface for specifying custom template information.
diff --git a/python/pystache/setup.py b/python/pystache/setup.py
index 0d99aae8fb..83e8cd398f 100644
--- a/python/pystache/setup.py
+++ b/python/pystache/setup.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# coding: utf-8
 
 """
 This script supports publishing Pystache to PyPI.
@@ -85,6 +84,7 @@ Push a tag to GitHub:
 
 """
 
+from __future__ import print_function
 import os
 import shutil
 import sys
@@ -170,7 +170,7 @@ def write(u, path):
     Write a unicode string to a file (as utf-8).
 
     """
-    print("writing to: %s" % path)
+    print(("writing to: %s" % path))
     # This function implementation was chosen to be compatible across Python 2/3.
     f = open(path, "wb")
     try:
@@ -200,7 +200,7 @@ def strip_html_comments(text):
     lines = text.splitlines(True)  # preserve line endings.
 
     # Remove HTML comments (which we only allow to take a special form).
-    new_lines = filter(lambda line: not line.startswith("<!--"), lines)
+    new_lines = [line for line in lines if not line.startswith("<!--")]
 
     return "".join(new_lines)
 
@@ -221,9 +221,9 @@ def convert_md_to_rst(md_path, rst_temp_path):
 
     """
     # Pandoc uses the UTF-8 character encoding for both input and output.
-    command = "pandoc --write=rst --output=%s %s" % (rst_temp_path, md_path)
-    print("converting with pandoc: %s to %s\n-->%s" % (md_path, rst_temp_path,
-                                                       command))
+    command = "pandoc --write=rst --output={} {}".format(rst_temp_path, md_path)
+    print(("converting with pandoc: {} to {}\n-->{}".format(md_path, rst_temp_path,
+                                                       command)))
 
     if os.path.exists(rst_temp_path):
         os.remove(rst_temp_path)
@@ -290,17 +290,17 @@ def publish():
     long_description = make_long_description()
 
     if long_description != read(RST_DESCRIPTION_PATH):
-        print("""\
-Description file not up-to-date: %s
+        print(("""\
+Description file not up-to-date: {}
 Run the following command and commit the changes--
 
-    python setup.py %s
-""" % (RST_DESCRIPTION_PATH, PREP_COMMAND))
+    python setup.py {}
+""".format(RST_DESCRIPTION_PATH, PREP_COMMAND)))
         sys.exit()
 
-    print("Description up-to-date: %s" % RST_DESCRIPTION_PATH)
+    print(("Description up-to-date: %s" % RST_DESCRIPTION_PATH))
 
-    answer = raw_input("Are you sure you want to publish to PyPI (yes/no)?")
+    answer = input("Are you sure you want to publish to PyPI (yes/no)?")
 
     if answer != "yes":
         exit("Aborted: nothing published")
@@ -365,7 +365,7 @@ def main(sys_argv):
 
     # TODO: use the logging module instead of printing.
     # TODO: include the following in a verbose mode.
-    sys.stderr.write("pystache: using: version %s of %s\n" % (repr(dist.__version__), repr(dist)))
+    sys.stderr.write("pystache: using: version {} of {}\n".format(repr(dist.__version__), repr(dist)))
 
     command = sys_argv[-1]
 
diff --git a/python/pystache/test_pystache.py b/python/pystache/test_pystache.py
index 9a1a3ca26d..dc99f06ee8 100644
--- a/python/pystache/test_pystache.py
+++ b/python/pystache/test_pystache.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# coding: utf-8
 
 """
 Runs project tests.
diff --git a/python/pytest/_pytest/_argcomplete.py b/python/pytest/_pytest/_argcomplete.py
index 955855a964..58bccb66b9 100644
--- a/python/pytest/_pytest/_argcomplete.py
+++ b/python/pytest/_pytest/_argcomplete.py
@@ -1,4 +1,3 @@
-
 """allow bash-completion for argparse with argcomplete if installed
 needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
 to find the magic string, so _ARGCOMPLETE env. var is never set, and
diff --git a/python/pytest/_pytest/_code/_py2traceback.py b/python/pytest/_pytest/_code/_py2traceback.py
index a830d9899a..2661738c10 100644
--- a/python/pytest/_pytest/_code/_py2traceback.py
+++ b/python/pytest/_pytest/_code/_py2traceback.py
@@ -23,7 +23,7 @@ def format_exception_only(etype, value):
 
     # An instance should not have a meaningful value parameter, but
     # sometimes does, particularly for string exceptions, such as
-    # >>> raise string1, string2  # deprecated
+    # >>> raise string1(string2  # deprecated)
     #
     # Clear these out first because issubtype(string1, SyntaxError)
     # would throw another exception and mask the original problem.
@@ -49,7 +49,7 @@ def format_exception_only(etype, value):
         if badline is not None:
             if isinstance(badline, bytes):  # python 2 only
                 badline = badline.decode('utf-8', 'replace')
-            lines.append(u'    %s\n' % badline.strip())
+            lines.append('    %s\n' % badline.strip())
             if offset is not None:
                 caretspace = badline.rstrip('\n')[:offset].lstrip()
                 # non-space whitespace (likes tabs) must be kept for alignment
@@ -67,12 +67,12 @@ def _format_final_exc_line(etype, value):
     if value is None or not valuestr:
         line = "%s\n" % etype
     else:
-        line = "%s: %s\n" % (etype, valuestr)
+        line = "{}: {}\n".format(etype, valuestr)
     return line
 
 def _some_str(value):
     try:
-        return unicode(value)
+        return str(value)
     except Exception:
         try:
             return str(value)
diff --git a/python/pytest/_pytest/_code/code.py b/python/pytest/_pytest/_code/code.py
index 8995cc1f71..1f0b3bd355 100644
--- a/python/pytest/_pytest/_code/code.py
+++ b/python/pytest/_pytest/_code/code.py
@@ -7,12 +7,9 @@ builtin_repr = repr
 
 reprlib = py.builtin._tryimport('repr', 'reprlib')
 
-if sys.version_info[0] >= 3:
-    from traceback import format_exception_only
-else:
-    from ._py2traceback import format_exception_only
+from traceback import format_exception_only
 
-class Code(object):
+class Code:
     """ wrapper around Python code objects """
     def __init__(self, rawcode):
         if not hasattr(rawcode, "co_filename"):
@@ -72,7 +69,7 @@ class Code(object):
             argcount += raw.co_flags & CO_VARKEYWORDS
         return raw.co_varnames[:argcount]
 
-class Frame(object):
+class Frame:
     """Wrapper around a Python frame holding f_locals and f_globals
     in which expressions can be evaluated."""
 
@@ -133,7 +130,7 @@ class Frame(object):
                 pass     # this can occur when using Psyco
         return retval
 
-class TracebackEntry(object):
+class TracebackEntry:
     """ a single entry in a traceback """
 
     _repr_style = None
@@ -182,7 +179,7 @@ class TracebackEntry(object):
             source = py.builtin._totext(self.statement).strip()
             x = reinterpret(source, self.frame, should_fail=True)
             if not py.builtin._istext(x):
-                raise TypeError("interpret returned non-string %r" % (x,))
+                raise TypeError("interpret returned non-string {!r}".format(x))
             self.exprinfo = x
         return self.exprinfo
 
@@ -286,7 +283,7 @@ class Traceback(list):
         return self
 
     def __getitem__(self, key):
-        val = super(Traceback, self).__getitem__(key)
+        val = super().__getitem__(key)
         if isinstance(key, type(slice(0))):
             val = self.__class__(val)
         return val
@@ -301,7 +298,7 @@ class Traceback(list):
             by default this removes all the TracebackEntries which are hidden
             (see ishidden() above)
         """
-        return Traceback(filter(fn, self))
+        return Traceback(list(filter(fn, self)))
 
     def getcrashentry(self):
         """ return last non-hidden traceback entry that lead
@@ -340,7 +337,7 @@ class Traceback(list):
 co_equal = compile('__recursioncache_locals_1 == __recursioncache_locals_2',
                    '?', 'eval')
 
-class ExceptionInfo(object):
+class ExceptionInfo:
     """ wraps sys.exc_info() objects and offers
         help for navigating the traceback.
     """
@@ -425,10 +422,10 @@ class ExceptionInfo(object):
     def __unicode__(self):
         entry = self.traceback[-1]
         loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
-        return unicode(loc)
+        return str(loc)
 
 
-class FormattedExcinfo(object):
+class FormattedExcinfo:
     """ presenting information about failing Functions and Generators. """
     # for traceback entries
     flow_marker = ">"
@@ -703,7 +700,7 @@ class ReprEntry(TerminalRepr):
             self.reprfileloc.toterminal(tw)
 
     def __str__(self):
-        return "%s\n%s\n%s" % ("\n".join(self.lines),
+        return "{}\n{}\n{}".format("\n".join(self.lines),
                                self.reprlocals,
                                self.reprfileloc)
 
diff --git a/python/pytest/_pytest/_code/source.py b/python/pytest/_pytest/_code/source.py
index a1521f8a21..36ba5bc9d2 100644
--- a/python/pytest/_pytest/_code/source.py
+++ b/python/pytest/_pytest/_code/source.py
@@ -1,5 +1,3 @@
-from __future__ import generators
-
 from bisect import bisect_right
 import sys
 import inspect, tokenize
@@ -15,7 +13,7 @@ except ImportError:
     _ast = None
 
 
-class Source(object):
+class Source:
     """ a immutable object holding a source code fragment,
         possibly deindenting it.
     """
@@ -193,14 +191,13 @@ class Source(object):
             if flag & _AST_FLAG:
                 return co
             lines = [(x + "\n") for x in self.lines]
-            if sys.version_info[0] >= 3:
-                # XXX py3's inspect.getsourcefile() checks for a module
-                # and a pep302 __loader__ ... we don't have a module
-                # at code compile-time so we need to fake it here
-                m = ModuleType("_pycodecompile_pseudo_module")
-                py.std.inspect.modulesbyfile[filename] = None
-                py.std.sys.modules[None] = m
-                m.__loader__ = 1
+            # XXX py3's inspect.getsourcefile() checks for a module
+            # and a pep302 __loader__ ... we don't have a module
+            # at code compile-time so we need to fake it here
+            m = ModuleType("_pycodecompile_pseudo_module")
+            py.std.inspect.modulesbyfile[filename] = None
+            py.std.sys.modules[None] = m
+            m.__loader__ = 1
             py.std.linecache.cache[filename] = (1, None, lines, filename)
             return co
 
@@ -243,7 +240,7 @@ def getfslineno(obj):
         if fspath:
             try:
                 _, lineno = findsource(obj)
-            except IOError:
+            except OSError:
                 pass
     else:
         fspath = code.path
diff --git a/python/pytest/_pytest/assertion/__init__.py b/python/pytest/_pytest/assertion/__init__.py
index 6921deb2a6..67cefa8d07 100644
--- a/python/pytest/_pytest/assertion/__init__.py
+++ b/python/pytest/_pytest/assertion/__init__.py
@@ -70,7 +70,7 @@ def pytest_configure(config):
     warn_about_missing_assertion(mode)
     config._assertstate = AssertionState(config, mode)
     config._assertstate.hook = hook
-    config._assertstate.trace("configured with mode set to %r" % (mode,))
+    config._assertstate.trace("configured with mode set to {!r}".format(mode))
     def undo():
         hook = config._assertstate.hook
         if hook is not None and hook in sys.meta_path:
diff --git a/python/pytest/_pytest/assertion/reinterpret.py b/python/pytest/_pytest/assertion/reinterpret.py
index f4262c3ace..7615c1bcf7 100644
--- a/python/pytest/_pytest/assertion/reinterpret.py
+++ b/python/pytest/_pytest/assertion/reinterpret.py
@@ -49,8 +49,7 @@ class AssertionError(util.BuiltinAssertionError):
             if not self.args:
                 self.args = (self.msg,)
 
-if sys.version_info > (3, 0):
-    AssertionError.__module__ = "builtins"
+AssertionError.__module__ = "builtins"
 
 if sys.platform.startswith("java"):
     # See http://bugs.jython.org/issue1497
@@ -62,8 +61,8 @@ if sys.platform.startswith("java"):
               "AugAssign", "Print", "For", "While", "If", "With", "Raise",
               "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom",
               "Exec", "Global", "Expr", "Pass", "Break", "Continue")
-    _expr_nodes = set(getattr(ast, name) for name in _exprs)
-    _stmt_nodes = set(getattr(ast, name) for name in _stmts)
+    _expr_nodes = {getattr(ast, name) for name in _exprs}
+    _stmt_nodes = {getattr(ast, name) for name in _stmts}
     def _is_ast_expr(node):
         return node.__class__ in _expr_nodes
     def _is_ast_stmt(node):
@@ -78,7 +77,7 @@ try:
     _Starred = ast.Starred
 except AttributeError:
     # Python 2. Define a dummy class so isinstance() will always be False.
-    class _Starred(object): pass
+    class _Starred: pass
 
 
 class Failure(Exception):
@@ -112,9 +111,9 @@ def getfailure(e):
     value = e.cause[1]
     if str(value):
         lines = explanation.split('\n')
-        lines[0] += "  << %s" % (value,)
+        lines[0] += "  << {}".format(value)
         explanation = '\n'.join(lines)
-    text = "%s: %s" % (e.cause[0].__name__, explanation)
+    text = "{}: {}".format(e.cause[0].__name__, explanation)
     if text.startswith('AssertionError: assert '):
         text = text[16:]
     return text
@@ -193,7 +192,7 @@ class DebugInterpreter(ast.NodeVisitor):
     def visit_Name(self, name):
         explanation, result = self.generic_visit(name)
         # See if the name is local.
-        source = "%r in locals() is not globals()" % (name.id,)
+        source = "{!r} in locals() is not globals()".format(name.id)
         co = self._compile(source)
         try:
             local = self.frame.eval(co)
@@ -210,9 +209,9 @@ class DebugInterpreter(ast.NodeVisitor):
         for op, next_op in zip(comp.ops, comp.comparators):
             next_explanation, next_result = self.visit(next_op)
             op_symbol = operator_map[op.__class__]
-            explanation = "%s %s %s" % (left_explanation, op_symbol,
+            explanation = "{} {} {}".format(left_explanation, op_symbol,
                                         next_explanation)
-            source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,)
+            source = "__exprinfo_left {} __exprinfo_right".format(op_symbol)
             co = self._compile(source)
             try:
                 result = self.frame.eval(co, __exprinfo_left=left_result,
@@ -261,9 +260,9 @@ class DebugInterpreter(ast.NodeVisitor):
         left_explanation, left_result = self.visit(binop.left)
         right_explanation, right_result = self.visit(binop.right)
         symbol = operator_map[binop.op.__class__]
-        explanation = "(%s %s %s)" % (left_explanation, symbol,
+        explanation = "({} {} {})".format(left_explanation, symbol,
                                       right_explanation)
-        source = "__exprinfo_left %s __exprinfo_right" % (symbol,)
+        source = "__exprinfo_left {} __exprinfo_right".format(symbol)
         co = self._compile(source)
         try:
             result = self.frame.eval(co, __exprinfo_left=left_result,
@@ -282,24 +281,24 @@ class DebugInterpreter(ast.NodeVisitor):
             if isinstance(arg, _Starred):
                 arg_name = "__exprinfo_star"
                 ns[arg_name] = arg_result
-                arguments.append("*%s" % (arg_name,))
-                arg_explanations.append("*%s" % (arg_explanation,))
+                arguments.append("*{}".format(arg_name))
+                arg_explanations.append("*{}".format(arg_explanation))
             else:
-                arg_name = "__exprinfo_%s" % (len(ns),)
+                arg_name = "__exprinfo_{}".format(len(ns))
                 ns[arg_name] = arg_result
                 arguments.append(arg_name)
                 arg_explanations.append(arg_explanation)
         for keyword in call.keywords:
             arg_explanation, arg_result = self.visit(keyword.value)
             if keyword.arg:
-                arg_name = "__exprinfo_%s" % (len(ns),)
+                arg_name = "__exprinfo_{}".format(len(ns))
                 keyword_source = "%s=%%s" % (keyword.arg)
                 arguments.append(keyword_source % (arg_name,))
                 arg_explanations.append(keyword_source % (arg_explanation,))
             else:
                 arg_name = "__exprinfo_kwds"
-                arguments.append("**%s" % (arg_name,))
-                arg_explanations.append("**%s" % (arg_explanation,))
+                arguments.append("**{}".format(arg_name))
+                arg_explanations.append("**{}".format(arg_explanation))
 
             ns[arg_name] = arg_result
 
@@ -307,19 +306,19 @@ class DebugInterpreter(ast.NodeVisitor):
             arg_explanation, arg_result = self.visit(call.starargs)
             arg_name = "__exprinfo_star"
             ns[arg_name] = arg_result
-            arguments.append("*%s" % (arg_name,))
-            arg_explanations.append("*%s" % (arg_explanation,))
+            arguments.append("*{}".format(arg_name))
+            arg_explanations.append("*{}".format(arg_explanation))
 
         if getattr(call, 'kwargs', None):
             arg_explanation, arg_result = self.visit(call.kwargs)
             arg_name = "__exprinfo_kwds"
             ns[arg_name] = arg_result
-            arguments.append("**%s" % (arg_name,))
-            arg_explanations.append("**%s" % (arg_explanation,))
+            arguments.append("**{}".format(arg_name))
+            arg_explanations.append("**{}".format(arg_explanation))
         args_explained = ", ".join(arg_explanations)
-        explanation = "%s(%s)" % (func_explanation, args_explained)
+        explanation = "{}({})".format(func_explanation, args_explained)
         args = ", ".join(arguments)
-        source = "__exprinfo_func(%s)" % (args,)
+        source = "__exprinfo_func({})".format(args)
         co = self._compile(source)
         try:
             result = self.frame.eval(co, **ns)
@@ -343,8 +342,8 @@ class DebugInterpreter(ast.NodeVisitor):
         if not isinstance(attr.ctx, ast.Load):
             return self.generic_visit(attr)
         source_explanation, source_result = self.visit(attr.value)
-        explanation = "%s.%s" % (source_explanation, attr.attr)
-        source = "__exprinfo_expr.%s" % (attr.attr,)
+        explanation = "{}.{}".format(source_explanation, attr.attr)
+        source = "__exprinfo_expr.{}".format(attr.attr)
         co = self._compile(source)
         try:
             try:
@@ -357,12 +356,12 @@ class DebugInterpreter(ast.NodeVisitor):
                 co = self._compile(source)
                 class_name = self.frame.eval(co, __exprinfo_expr=source_result)
                 mangled_attr = "_" + class_name +  attr.attr
-                source = "__exprinfo_expr.%s" % (mangled_attr,)
+                source = "__exprinfo_expr.{}".format(mangled_attr)
                 co = self._compile(source)
                 result = self.frame.eval(co, __exprinfo_expr=source_result)
         except Exception:
             raise Failure(explanation)
-        explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),
+        explanation = "{}\n{{{} = {}.{}\n}}".format(self.frame.repr(result),
                                               self.frame.repr(result),
                                               source_explanation, attr.attr)
         # Check if the attr is from an instance.
@@ -381,7 +380,7 @@ class DebugInterpreter(ast.NodeVisitor):
 
     def visit_Assert(self, assrt):
         test_explanation, test_result = self.visit(assrt.test)
-        explanation = "assert %s" % (test_explanation,)
+        explanation = "assert {}".format(test_explanation)
         if not self.frame.is_true(test_result):
             try:
                 raise util.BuiltinAssertionError
@@ -391,7 +390,7 @@ class DebugInterpreter(ast.NodeVisitor):
 
     def visit_Assign(self, assign):
         value_explanation, value_result = self.visit(assign.value)
-        explanation = "... = %s" % (value_explanation,)
+        explanation = "... = {}".format(value_explanation)
         name = ast.Name("__exprinfo_expr", ast.Load(),
                         lineno=assign.value.lineno,
                         col_offset=assign.value.col_offset)
diff --git a/python/pytest/_pytest/assertion/rewrite.py b/python/pytest/_pytest/assertion/rewrite.py
index 14b8e49db2..8275fe997e 100644
--- a/python/pytest/_pytest/assertion/rewrite.py
+++ b/python/pytest/_pytest/assertion/rewrite.py
@@ -26,7 +26,7 @@ else:
     else:
         impl = "cpython"
     ver = sys.version_info
-    PYTEST_TAG = "%s-%s%s-PYTEST" % (impl, ver[0], ver[1])
+    PYTEST_TAG = "{}-{}{}-PYTEST".format(impl, ver[0], ver[1])
     del ver, impl
 
 PYC_EXT = ".py" + (__debug__ and "c" or "o")
@@ -41,7 +41,7 @@ else:
     ast_Call = lambda a,b,c: ast.Call(a, b, c, None, None)
 
 
-class AssertionRewritingHook(object):
+class AssertionRewritingHook:
     """PEP302 Import hook which rewrites asserts."""
 
     def __init__(self):
@@ -95,7 +95,7 @@ class AssertionRewritingHook(object):
             try:
                 for pat in self.fnpats:
                     if fn_pypath.fnmatch(pat):
-                        state.trace("matched test file %r" % (fn,))
+                        state.trace("matched test file {!r}".format(fn))
                         break
                 else:
                     return None
@@ -139,7 +139,7 @@ class AssertionRewritingHook(object):
         # to check for a cached pyc. This may not be optimal...
         co = _read_pyc(fn_pypath, pyc, state.trace)
         if co is None:
-            state.trace("rewriting %r" % (fn,))
+            state.trace("rewriting {!r}".format(fn))
             source_stat, co = _rewrite_test(state, fn_pypath)
             if co is None:
                 # Probably a SyntaxError in the test.
@@ -147,7 +147,7 @@ class AssertionRewritingHook(object):
             if write:
                 _make_rewritten_pyc(state, source_stat, pyc, co)
         else:
-            state.trace("found cached rewritten pyc for %r" % (fn,))
+            state.trace("found cached rewritten pyc for {!r}".format(fn))
         self.modules[name] = co, pyc
         return self
 
@@ -218,7 +218,7 @@ def _write_pyc(state, co, source_stat, pyc):
     # the comment in load_module above.)
     try:
         fp = open(pyc, "wb")
-    except IOError:
+    except OSError:
         err = sys.exc_info()[1].errno
         state.trace("error writing pyc file at %s: errno=%s" %(pyc, err))
         # we ignore any failure to write the cache file
@@ -235,8 +235,8 @@ def _write_pyc(state, co, source_stat, pyc):
         fp.close()
     return True
 
-RN = "\r\n".encode("utf-8")
-N = "\n".encode("utf-8")
+RN = b"\r\n"
+N = b"\n"
 
 cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+")
 BOM_UTF8 = '\xef\xbb\xbf'
@@ -246,7 +246,7 @@ def _rewrite_test(state, fn):
     try:
         stat = fn.stat()
         source = fn.read("rb")
-    except EnvironmentError:
+    except OSError:
         return None, None
     if ASCII_IS_DEFAULT_ENCODING:
         # ASCII is the default encoding in Python 2. Without a coding
@@ -285,7 +285,7 @@ def _rewrite_test(state, fn):
         tree = ast.parse(source)
     except SyntaxError:
         # Let this pop up again in the real import.
-        state.trace("failed to parse: %r" % (fn,))
+        state.trace("failed to parse: {!r}".format(fn))
         return None, None
     rewrite_asserts(tree)
     try:
@@ -293,7 +293,7 @@ def _rewrite_test(state, fn):
     except SyntaxError:
         # It's possible that this error is from some bug in the
         # assertion rewriting, but I don't know of a fast way to tell.
-        state.trace("failed to compile: %r" % (fn,))
+        state.trace("failed to compile: {!r}".format(fn))
         return None, None
     return stat, co
 
@@ -317,15 +317,15 @@ def _read_pyc(source, pyc, trace=lambda x: None):
     """
     try:
         fp = open(pyc, "rb")
-    except IOError:
+    except OSError:
         return None
     with fp:
         try:
             mtime = int(source.mtime())
             size = source.size()
             data = fp.read(12)
-        except EnvironmentError as e:
-            trace('_read_pyc(%s): EnvironmentError %s' % (source, e))
+        except OSError as e:
+            trace('_read_pyc({}): EnvironmentError {}'.format(source, e))
             return None
         # Check for invalid or out of date pyc file.
         if (len(data) != 12 or data[:4] != imp.get_magic() or
@@ -335,7 +335,7 @@ def _read_pyc(source, pyc, trace=lambda x: None):
         try:
             co = marshal.load(fp)
         except Exception as e:
-            trace('_read_pyc(%s): marshal.load error %s' % (source, e))
+            trace('_read_pyc({}): marshal.load error {}'.format(source, e))
             return None
         if not isinstance(co, types.CodeType):
             trace('_read_pyc(%s): not a code object' % source)
@@ -408,7 +408,7 @@ def _format_boolop(explanations, is_or):
     return explanation.replace(t('%'), t('%%'))
 
 def _call_reprcompare(ops, results, expls, each_obj):
-    for i, res, expl in zip(range(len(ops)), results, expls):
+    for i, res, expl in zip(list(range(len(ops))), results, expls):
         try:
             done = not res
         except Exception:
@@ -695,10 +695,7 @@ class AssertionRewriter(ast.NodeVisitor):
         fmt = self.helper("format_explanation", msg)
         err_name = ast.Name("AssertionError", ast.Load())
         exc = ast_Call(err_name, [fmt], [])
-        if sys.version_info[0] >= 3:
-            raise_ = ast.Raise(exc, None)
-        else:
-            raise_ = ast.Raise(exc, None, None)
+        raise_ = ast.Raise(exc, None)
         body.append(raise_)
         # Clear temporary variables by setting them to None.
         if self.variables:
@@ -766,7 +763,7 @@ class AssertionRewriter(ast.NodeVisitor):
         symbol = binop_map[binop.op.__class__]
         left_expr, left_expl = self.visit(binop.left)
         right_expr, right_expl = self.visit(binop.right)
-        explanation = "(%s %s %s)" % (left_expl, symbol, right_expl)
+        explanation = "({} {} {})".format(left_expl, symbol, right_expl)
         res = self.assign(ast.BinOp(left_expr, binop.op, right_expr))
         return res, explanation
 
@@ -790,11 +787,11 @@ class AssertionRewriter(ast.NodeVisitor):
             else: ## **args have `arg` keywords with an .arg of None
                 arg_expls.append("**" + expl)
 
-        expl = "%s(%s)" % (func_expl, ', '.join(arg_expls))
+        expl = "{}({})".format(func_expl, ', '.join(arg_expls))
         new_call = ast.Call(new_func, new_args, new_kwargs)
         res = self.assign(new_call)
         res_expl = self.explanation_param(self.display(res))
-        outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl)
+        outer_expl = "{}\n{{{} = {}\n}}".format(res_expl, res_expl, expl)
         return res, outer_expl
 
     def visit_Starred(self, starred):
@@ -825,12 +822,12 @@ class AssertionRewriter(ast.NodeVisitor):
         if call.kwargs:
             new_kwarg, expl = self.visit(call.kwargs)
             arg_expls.append("**" + expl)
-        expl = "%s(%s)" % (func_expl, ', '.join(arg_expls))
+        expl = "{}({})".format(func_expl, ', '.join(arg_expls))
         new_call = ast.Call(new_func, new_args, new_kwargs,
                             new_star, new_kwarg)
         res = self.assign(new_call)
         res_expl = self.explanation_param(self.display(res))
-        outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl)
+        outer_expl = "{}\n{{{} = {}\n}}".format(res_expl, res_expl, expl)
         return res, outer_expl
 
     # ast.Call signature changed on 3.5,
@@ -858,7 +855,7 @@ class AssertionRewriter(ast.NodeVisitor):
         res_variables = [self.variable() for i in range(len(comp.ops))]
         load_names = [ast.Name(v, ast.Load()) for v in res_variables]
         store_names = [ast.Name(v, ast.Store()) for v in res_variables]
-        it = zip(range(len(comp.ops)), comp.ops, comp.comparators)
+        it = list(zip(list(range(len(comp.ops))), comp.ops, comp.comparators))
         expls = []
         syms = []
         results = [left_res]
@@ -867,7 +864,7 @@ class AssertionRewriter(ast.NodeVisitor):
             results.append(next_res)
             sym = binop_map[op.__class__]
             syms.append(ast.Str(sym))
-            expl = "%s %s %s" % (left_expl, sym, next_expl)
+            expl = "{} {} {}".format(left_expl, sym, next_expl)
             expls.append(ast.Str(expl))
             res_expr = ast.Compare(left_res, [op], [next_res])
             self.statements.append(ast.Assign([store_names[i]], res_expr))
diff --git a/python/pytest/_pytest/assertion/util.py b/python/pytest/_pytest/assertion/util.py
index f2f23efea2..d384d804b3 100644
--- a/python/pytest/_pytest/assertion/util.py
+++ b/python/pytest/_pytest/assertion/util.py
@@ -4,7 +4,7 @@ import pprint
 import _pytest._code
 import py
 try:
-    from collections import Sequence
+    from collections.abc import Sequence
 except ImportError:
     Sequence = list
 
@@ -66,7 +66,7 @@ def _collapse_false(explanation):
                     break
             prev_c = c
         else:
-            raise AssertionError("unbalanced braces: %r" % (explanation,))
+            raise AssertionError("unbalanced braces: {!r}".format(explanation))
         end = start + i
         where = end
         if explanation[end - 1] == '\n':
@@ -130,9 +130,9 @@ def _format_lines(lines):
 
 # Provide basestring in python3
 try:
-    basestring = basestring
+    str = str
 except NameError:
-    basestring = str
+    str = str
 
 
 def assertrepr_compare(config, op, left, right):
@@ -144,8 +144,8 @@ def assertrepr_compare(config, op, left, right):
     summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
 
     issequence = lambda x: (isinstance(x, (list, tuple, Sequence)) and
-                            not isinstance(x, basestring))
-    istext = lambda x: isinstance(x, basestring)
+                            not isinstance(x, str))
+    istext = lambda x: isinstance(x, str)
     isdict = lambda x: isinstance(x, dict)
     isset = lambda x: isinstance(x, (set, frozenset))
 
@@ -287,14 +287,14 @@ def _compare_eq_set(left, right, verbose=False):
 def _compare_eq_dict(left, right, verbose=False):
     explanation = []
     common = set(left).intersection(set(right))
-    same = dict((k, left[k]) for k in common if left[k] == right[k])
+    same = {k: left[k] for k in common if left[k] == right[k]}
     if same and not verbose:
         explanation += [u('Omitting %s identical items, use -v to show') %
                         len(same)]
     elif same:
         explanation += [u('Common items:')]
         explanation += pprint.pformat(same).splitlines()
-    diff = set(k for k in common if left[k] != right[k])
+    diff = {k for k in common if left[k] != right[k]}
     if diff:
         explanation += [u('Differing items:')]
         for k in diff:
@@ -304,12 +304,12 @@ def _compare_eq_dict(left, right, verbose=False):
     if extra_left:
         explanation.append(u('Left contains more items:'))
         explanation.extend(pprint.pformat(
-            dict((k, left[k]) for k in extra_left)).splitlines())
+            {k: left[k] for k in extra_left}).splitlines())
     extra_right = set(right) - set(left)
     if extra_right:
         explanation.append(u('Right contains more items:'))
         explanation.extend(pprint.pformat(
-            dict((k, right[k]) for k in extra_right)).splitlines())
+            {k: right[k] for k in extra_right}).splitlines())
     return explanation
 
 
diff --git a/python/pytest/_pytest/cacheprovider.py b/python/pytest/_pytest/cacheprovider.py
index 0657001f2d..0606673060 100755
--- a/python/pytest/_pytest/cacheprovider.py
+++ b/python/pytest/_pytest/cacheprovider.py
@@ -11,7 +11,7 @@ import json
 from os.path import sep as _sep, altsep as _altsep
 
 
-class Cache(object):
+class Cache:
     def __init__(self, config):
         self.config = config
         self._cachedir = config.rootdir.join(".cache")
@@ -56,7 +56,7 @@ class Cache(object):
                 with path.open("r") as f:
                     return json.load(f)
             except ValueError:
-                self.trace("cache-invalid at %s" % (path,))
+                self.trace("cache-invalid at {}".format(path))
         return default
 
     def set(self, key, value):
@@ -73,17 +73,17 @@ class Cache(object):
             path.dirpath().ensure_dir()
         except (py.error.EEXIST, py.error.EACCES):
             self.config.warn(
-                code='I9', message='could not create cache path %s' % (path,)
+                code='I9', message='could not create cache path {}'.format(path)
             )
             return
         try:
             f = path.open('w')
         except py.error.ENOTDIR:
             self.config.warn(
-                code='I9', message='cache could not write path %s' % (path,))
+                code='I9', message='cache could not write path {}'.format(path))
         else:
             with f:
-                self.trace("cache-write %s: %r" % (key, value,))
+                self.trace("cache-write {}: {!r}".format(key, value))
                 json.dump(value, f, indent=2, sort_keys=True)
 
 
diff --git a/python/pytest/_pytest/capture.py b/python/pytest/_pytest/capture.py
index 3895a714aa..3b93f25c88 100644
--- a/python/pytest/_pytest/capture.py
+++ b/python/pytest/_pytest/capture.py
@@ -2,7 +2,6 @@
 per-test stdout/stderr capturing mechanism.
 
 """
-from __future__ import with_statement
 
 import sys
 import os
@@ -12,7 +11,7 @@ import py
 import pytest
 
 from py.io import TextIO
-unicode = py.builtin.text
+str = py.builtin.text
 
 patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
 
@@ -220,14 +219,14 @@ def safe_text_dupfile(f, mode, default_encoding="UTF8"):
     return EncodedFile(f, encoding or default_encoding)
 
 
-class EncodedFile(object):
+class EncodedFile:
     errors = "strict"  # possibly needed by py3 code (issue555)
     def __init__(self, buffer, encoding):
         self.buffer = buffer
         self.encoding = encoding
 
     def write(self, obj):
-        if isinstance(obj, unicode):
+        if isinstance(obj, str):
             obj = obj.encode(self.encoding, "replace")
         self.buffer.write(obj)
 
@@ -239,7 +238,7 @@ class EncodedFile(object):
         return getattr(object.__getattribute__(self, "buffer"), name)
 
 
-class MultiCapture(object):
+class MultiCapture:
     out = err = in_ = None
 
     def __init__(self, out=True, err=True, in_=True, Capture=None):
@@ -318,7 +317,7 @@ class FDCapture:
         else:
             if targetfd == 0:
                 assert not tmpfile, "cannot set tmpfile with stdin"
-                tmpfile = open(os.devnull, "r")
+                tmpfile = open(os.devnull)
                 self.syscapture = SysCapture(targetfd)
             else:
                 if tmpfile is None:
@@ -333,7 +332,7 @@ class FDCapture:
             self.tmpfile_fd = tmpfile.fileno()
 
     def __repr__(self):
-        return "<FDCapture %s oldfd=%s>" % (self.targetfd, self.targetfd_save)
+        return "<FDCapture {} oldfd={}>".format(self.targetfd, self.targetfd_save)
 
     def start(self):
         """ Start capturing on targetfd using memorized tmpfile. """
@@ -430,7 +429,7 @@ class DontReadFromInput:
     encoding = None
 
     def read(self, *args):
-        raise IOError("reading from stdin while output is captured")
+        raise OSError("reading from stdin while output is captured")
     readline = read
     readlines = read
     __iter__ = read
diff --git a/python/pytest/_pytest/config.py b/python/pytest/_pytest/config.py
index 9a308df2bb..a83781d7d5 100644
--- a/python/pytest/_pytest/config.py
+++ b/python/pytest/_pytest/config.py
@@ -103,7 +103,7 @@ def _prepareconfig(args=None, plugins=None):
         args = [str(args)]
     elif not isinstance(args, (tuple, list)):
         if not isinstance(args, str):
-            raise ValueError("not a string or argument list: %r" % (args,))
+            raise ValueError("not a string or argument list: {!r}".format(args))
         args = shlex.split(args, posix=sys.platform != "win32")
     config = get_config()
     pluginmanager = config.pluginmanager
@@ -131,7 +131,7 @@ class PytestPluginManager(PluginManager):
     * ``conftest.py`` loading during start-up;
     """
     def __init__(self):
-        super(PytestPluginManager, self).__init__("pytest", implprefix="pytest_")
+        super().__init__("pytest", implprefix="pytest_")
         self._conftest_plugins = set()
 
         # state related to local conftest plugins
@@ -177,14 +177,14 @@ class PytestPluginManager(PluginManager):
             return
 
         method = getattr(plugin, name)
-        opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name)
+        opts = super().parse_hookimpl_opts(plugin, name)
         if opts is not None:
             for name in ("tryfirst", "trylast", "optionalhook", "hookwrapper"):
                 opts.setdefault(name, hasattr(method, name))
         return opts
 
     def parse_hookspec_opts(self, module_or_class, name):
-        opts = super(PytestPluginManager, self).parse_hookspec_opts(
+        opts = super().parse_hookspec_opts(
                                                 module_or_class, name)
         if opts is None:
             method = getattr(module_or_class, name)
@@ -194,7 +194,7 @@ class PytestPluginManager(PluginManager):
         return opts
 
     def _verify_hook(self, hook, hookmethod):
-        super(PytestPluginManager, self)._verify_hook(hook, hookmethod)
+        super()._verify_hook(hook, hookmethod)
         if "__multicall__" in hookmethod.argnames:
             fslineno = _pytest._code.getfslineno(hookmethod.function)
             warning = dict(code="I1",
@@ -205,7 +205,7 @@ class PytestPluginManager(PluginManager):
             self._warn(warning)
 
     def register(self, plugin, name=None):
-        ret = super(PytestPluginManager, self).register(plugin, name)
+        ret = super().register(plugin, name)
         if ret:
             self.hook.pytest_plugin_registered.call_historic(
                       kwargs=dict(plugin=plugin, manager=self))
@@ -384,7 +384,7 @@ class PytestPluginManager(PluginManager):
         try:
             __import__(importspec)
         except ImportError as e:
-            new_exc = ImportError('Error importing plugin "%s": %s' % (modname, e))
+            new_exc = ImportError('Error importing plugin "{}": {}'.format(modname, e))
             # copy over name and path attributes
             for attr in ('name', 'path'):
                 if hasattr(e, attr):
@@ -531,7 +531,7 @@ class ArgumentError(Exception):
 
     def __str__(self):
         if self.option_id:
-            return "option %s: %s" % (self.option_id, self.msg)
+            return "option {}: {}".format(self.option_id, self.msg)
         else:
             return self.msg
 
@@ -722,7 +722,7 @@ class MyOptionParser(argparse.ArgumentParser):
                 if arg and arg[0] == '-':
                     lines = ['unrecognized arguments: %s' % (' '.join(argv))]
                     for k, v in sorted(self.extra_info.items()):
-                        lines.append('  %s: %s' % (k, v))
+                        lines.append('  {}: {}'.format(k, v))
                     self.error('\n'.join(lines))
             getattr(args, FILE_OR_DIR).extend(argv)
         return args
@@ -784,7 +784,7 @@ def _ensure_removed_sysmodule(modname):
     except KeyError:
         pass
 
-class CmdOptions(object):
+class CmdOptions:
     """ holds cmdline options as attributes."""
     def __init__(self, values=()):
         self.__dict__.update(values)
@@ -800,7 +800,7 @@ class Notset:
 notset = Notset()
 FILE_OR_DIR = 'file_or_dir'
 
-class Config(object):
+class Config:
     """ access to configuration values, pluginmanager and plugin hooks.  """
 
     def __init__(self, pluginmanager):
@@ -809,7 +809,7 @@ class Config(object):
         self.option = CmdOptions()
         _a = FILE_OR_DIR
         self._parser = Parser(
-            usage="%%(prog)s [options] [%s] [%s] [...]" % (_a, _a),
+            usage="%(prog)s [options] [{}] [{}] [...]".format(_a, _a),
             processopt=self._processopt,
         )
         #: a pluginmanager instance
@@ -926,7 +926,7 @@ class Config(object):
         try:
             self.pluginmanager.load_setuptools_entrypoints("pytest11")
         except ImportError as e:
-            self.warn("I2", "could not load setuptools entry import: %s" % (e,))
+            self.warn("I2", "could not load setuptools entry import: {}".format(e))
         self.pluginmanager.consider_env()
         self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy())
         if self.known_args_namespace.confcutdir is None and self.inifile:
@@ -1016,7 +1016,7 @@ class Config(object):
         elif type == "args":
             return shlex.split(value)
         elif type == "linelist":
-            return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
+            return [t for t in [x.strip() for x in value.split("\n")] if t]
         elif type == "bool":
             return bool(_strtobool(value.strip()))
         else:
@@ -1058,7 +1058,7 @@ class Config(object):
             if skip:
                 import pytest
                 pytest.skip("no %r option found" %(name,))
-            raise ValueError("no option named %r" % (name,))
+            raise ValueError("no option named {!r}".format(name))
 
     def getvalue(self, name, path=None):
         """ (deprecated, use getoption()) """
@@ -1189,4 +1189,4 @@ def _strtobool(val):
     elif val in ('n', 'no', 'f', 'false', 'off', '0'):
         return 0
     else:
-        raise ValueError("invalid truth value %r" % (val,))
+        raise ValueError("invalid truth value {!r}".format(val))
diff --git a/python/pytest/_pytest/doctest.py b/python/pytest/_pytest/doctest.py
index a57f7a4949..368487db28 100644
--- a/python/pytest/_pytest/doctest.py
+++ b/python/pytest/_pytest/doctest.py
@@ -1,5 +1,4 @@
 """ discover and run doctests in modules and test files."""
-from __future__ import absolute_import
 
 import traceback
 
@@ -61,7 +60,7 @@ class ReprFailDoctest(TerminalRepr):
 class DoctestItem(pytest.Item):
 
     def __init__(self, name, parent, runner=None, dtest=None):
-        super(DoctestItem, self).__init__(name, parent)
+        super().__init__(name, parent)
         self.runner = runner
         self.dtest = dtest
         self.obj = None
@@ -78,7 +77,7 @@ class DoctestItem(pytest.Item):
         self.runner.run(self.dtest)
 
     def repr_failure(self, excinfo):
-        import doctest
+        from . import doctest
         if excinfo.errisinstance((doctest.DocTestFailure,
                                   doctest.UnexpectedException)):
             doctestfailure = excinfo.value
@@ -104,7 +103,7 @@ class DoctestItem(pytest.Item):
                 lines = ['EXAMPLE LOCATION UNKNOWN, not showing all tests of that example']
                 indent = '>>>'
                 for line in example.source.splitlines():
-                    lines.append('??? %s %s' % (indent, line))
+                    lines.append('??? {} {}'.format(indent, line))
                     indent = '...'
             if excinfo.errisinstance(doctest.DocTestFailure):
                 lines += checker.output_difference(example,
@@ -116,14 +115,14 @@ class DoctestItem(pytest.Item):
                 lines += traceback.format_exception(*excinfo.value.exc_info)
             return ReprFailDoctest(reprlocation, lines)
         else:
-            return super(DoctestItem, self).repr_failure(excinfo)
+            return super().repr_failure(excinfo)
 
     def reportinfo(self):
         return self.fspath, None, "[doctest] %s" % self.name
 
 
 def _get_flag_lookup():
-    import doctest
+    from . import doctest
     return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
                 DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE,
                 NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE,
@@ -147,7 +146,7 @@ def get_optionflags(parent):
 class DoctestTextfile(DoctestItem, pytest.Module):
 
     def runtest(self):
-        import doctest
+        from . import doctest
         fixture_request = _setup_fixtures(self)
 
         # inspired by doctest.testfile; ideally we would use it directly,
@@ -173,7 +172,7 @@ def _check_all_skipped(test):
     """raises pytest.skip() if all examples in the given DocTest have the SKIP
     option set.
     """
-    import doctest
+    from . import doctest
     all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
     if all_skipped:
         pytest.skip('all tests skipped by +SKIP option')
@@ -181,7 +180,7 @@ def _check_all_skipped(test):
 
 class DoctestModule(pytest.Module):
     def collect(self):
-        import doctest
+        from . import doctest
         if self.fspath.basename == "conftest.py":
             module = self.config.pluginmanager._importconftest(self.fspath)
         else:
@@ -231,7 +230,7 @@ def _get_checker():
     if hasattr(_get_checker, 'LiteralsOutputChecker'):
         return _get_checker.LiteralsOutputChecker()
 
-    import doctest
+    from . import doctest
     import re
 
     class LiteralsOutputChecker(doctest.OutputChecker):
@@ -278,7 +277,7 @@ def _get_allow_unicode_flag():
     """
     Registers and returns the ALLOW_UNICODE flag.
     """
-    import doctest
+    from . import doctest
     return doctest.register_optionflag('ALLOW_UNICODE')
 
 
@@ -286,5 +285,5 @@ def _get_allow_bytes_flag():
     """
     Registers and returns the ALLOW_BYTES flag.
     """
-    import doctest
+    from . import doctest
     return doctest.register_optionflag('ALLOW_BYTES')
diff --git a/python/pytest/_pytest/helpconfig.py b/python/pytest/_pytest/helpconfig.py
index 1df0c56ac7..ac6e9f0a5c 100644
--- a/python/pytest/_pytest/helpconfig.py
+++ b/python/pytest/_pytest/helpconfig.py
@@ -76,7 +76,7 @@ def showhelp(config):
         help, type, default = config._parser._inidict[name]
         if type is None:
             type = "string"
-        spec = "%s (%s)" % (name, type)
+        spec = "{} ({})".format(name, type)
         line = "  %-24s %s" %(spec, help)
         tw.line(line[:tw.fullwidth])
 
@@ -113,7 +113,7 @@ def getpluginversioninfo(config):
         lines.append("setuptools registered plugins:")
         for plugin, dist in plugininfo:
             loc = getattr(plugin, '__file__', repr(plugin))
-            content = "%s-%s at %s" % (dist.project_name, dist.version, loc)
+            content = "{}-{} at {}".format(dist.project_name, dist.version, loc)
             lines.append("  " + content)
     return lines
 
diff --git a/python/pytest/_pytest/junitxml.py b/python/pytest/_pytest/junitxml.py
index f4de1343ed..aa54a608e0 100644
--- a/python/pytest/_pytest/junitxml.py
+++ b/python/pytest/_pytest/junitxml.py
@@ -14,14 +14,12 @@ import re
 import sys
 import time
 import pytest
+unichr = chr
 
 # Python 2.X and 3.X compatibility
-if sys.version_info[0] < 3:
-    from codecs import open
-else:
-    unichr = chr
-    unicode = str
-    long = int
+unichr = chr
+str = str
+long = int
 
 
 class Junit(py.xml.Namespace):
@@ -37,11 +35,11 @@ _legal_ranges = (
     (0x20, 0x7E), (0x80, 0xD7FF), (0xE000, 0xFFFD), (0x10000, 0x10FFFF),
 )
 _legal_xml_re = [
-    unicode("%s-%s") % (unichr(low), unichr(high))
+    str("%s-%s") % (unichr(low), unichr(high))
     for (low, high) in _legal_ranges if low < sys.maxunicode
 ]
 _legal_xml_re = [unichr(x) for x in _legal_chars] + _legal_xml_re
-illegal_xml_re = re.compile(unicode('[^%s]') % unicode('').join(_legal_xml_re))
+illegal_xml_re = re.compile(str('[^%s]') % str('').join(_legal_xml_re))
 del _legal_chars
 del _legal_ranges
 del _legal_xml_re
@@ -53,14 +51,14 @@ def bin_xml_escape(arg):
     def repl(matchobj):
         i = ord(matchobj.group())
         if i <= 0xFF:
-            return unicode('#x%02X') % i
+            return str('#x%02X') % i
         else:
-            return unicode('#x%04X') % i
+            return str('#x%04X') % i
 
     return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(arg)))
 
 
-class _NodeReporter(object):
+class _NodeReporter:
     def __init__(self, nodeid, xml):
 
         self.id = nodeid
@@ -139,7 +137,7 @@ class _NodeReporter(object):
         else:
             if hasattr(report.longrepr, "reprcrash"):
                 message = report.longrepr.reprcrash.message
-            elif isinstance(report.longrepr, (unicode, str)):
+            elif isinstance(report.longrepr, (str, str)):
                 message = report.longrepr
             else:
                 message = str(report.longrepr)
@@ -173,13 +171,13 @@ class _NodeReporter(object):
             if skipreason.startswith("Skipped: "):
                 skipreason = bin_xml_escape(skipreason[9:])
             self.append(
-                Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason),
+                Junit.skipped("{}:{}: {}".format(filename, lineno, skipreason),
                               type="pytest.skip",
                               message=skipreason))
         self._write_captured_output(report)
 
     def finalize(self):
-        data = self.to_xml().unicode(indent=0)
+        data = self.to_xml().str(indent=0)
         self.__dict__.clear()
         self.to_xml = lambda: py.xml.raw(data)
 
@@ -252,7 +250,7 @@ def mangle_test_address(address):
     return names
 
 
-class LogXML(object):
+class LogXML:
     def __init__(self, logfile, prefix):
         logfile = os.path.expanduser(os.path.expandvars(logfile))
         self.logfile = os.path.normpath(os.path.abspath(logfile))
@@ -379,7 +377,7 @@ class LogXML(object):
             failures=self.stats['failure'],
             skips=self.stats['skipped'],
             tests=numtests,
-            time="%.3f" % suite_time_delta, ).unicode(indent=0))
+            time="%.3f" % suite_time_delta, ).str(indent=0))
         logfile.close()
 
     def pytest_terminal_summary(self, terminalreporter):
diff --git a/python/pytest/_pytest/main.py b/python/pytest/_pytest/main.py
index 8654d7af62..5d9598bb66 100644
--- a/python/pytest/_pytest/main.py
+++ b/python/pytest/_pytest/main.py
@@ -9,7 +9,7 @@ import _pytest._code
 import py
 import pytest
 try:
-    from collections import MutableMapping as MappingMixin
+    from collections.abc import MutableMapping as MappingMixin
 except ImportError:
     from UserDict import DictMixin as MappingMixin
 
@@ -25,7 +25,7 @@ EXIT_INTERNALERROR = 3
 EXIT_USAGEERROR = 4
 EXIT_NOTESTSCOLLECTED = 5
 
-name_re = re.compile("^[a-zA-Z_]\w*$")
+name_re = re.compile(r"^[a-zA-Z_]\w*$")
 
 def pytest_addoption(parser):
     parser.addini("norecursedirs", "directory patterns to avoid for recursion",
@@ -212,10 +212,10 @@ class NodeKeywords(MappingMixin):
         return list(self)
 
     def __repr__(self):
-        return "<NodeKeywords for node %s>" % (self.node, )
+        return "<NodeKeywords for node {}>".format(self.node)
 
 
-class Node(object):
+class Node:
     """ base class for Collector and Item the test collection tree.
     Collector subclasses have children, Items are terminal nodes."""
 
@@ -451,7 +451,7 @@ class FSCollector(Collector):
             if rel:
                 name = rel
             name = name.replace(os.sep, "/")
-        super(FSCollector, self).__init__(name, parent, config, session)
+        super().__init__(name, parent, config, session)
         self.fspath = fspath
 
     def _makeid(self):
@@ -470,7 +470,7 @@ class Item(Node):
     nextitem = None
 
     def __init__(self, name, parent=None, config=None, session=None):
-        super(Item, self).__init__(name, parent, config, session)
+        super().__init__(name, parent, config, session)
         self._report_sections = []
 
     def add_report_section(self, when, key, content):
@@ -589,8 +589,8 @@ class Session(FSCollector):
         if self._notfound:
             errors = []
             for arg, exc in self._notfound:
-                line = "(no name %r in any of %r)" % (arg, exc.args[0])
-                errors.append("not found: %s\n%s" % (arg, line))
+                line = "(no name {!r} in any of {!r})".format(arg, exc.args[0])
+                errors.append("not found: {}\n{}".format(arg, line))
                 #XXX: test this
             raise pytest.UsageError(*errors)
         if not genitems:
@@ -607,8 +607,7 @@ class Session(FSCollector):
             self.trace("processing argument", arg)
             self.trace.root.indent += 1
             try:
-                for x in self._collect(arg):
-                    yield x
+                yield from self._collect(arg)
             except NoMatch:
                 # we are inside a make_report hook so
                 # we cannot directly pass through the exception
@@ -739,6 +738,5 @@ class Session(FSCollector):
             rep = collect_one_node(node)
             if rep.passed:
                 for subnode in rep.result:
-                    for x in self.genitems(subnode):
-                        yield x
+                    yield from self.genitems(subnode)
             node.ihook.pytest_collectreport(report=rep)
diff --git a/python/pytest/_pytest/mark.py b/python/pytest/_pytest/mark.py
index d8b60def36..e30169292f 100644
--- a/python/pytest/_pytest/mark.py
+++ b/python/pytest/_pytest/mark.py
@@ -196,7 +196,7 @@ class MarkGenerator:
             x = beginning[0].split("(", 1)[0]
             l.add(x)
         if name not in self._markers:
-            raise AttributeError("%r not a registered marker" % (name,))
+            raise AttributeError("{!r} not a registered marker".format(name))
 
 def istestfunc(func):
     return hasattr(func, "__call__") and \
@@ -247,7 +247,7 @@ class MarkDecorator:
     def __repr__(self):
         d = self.__dict__.copy()
         name = d.pop('name')
-        return "<MarkDecorator %r %r>" % (name, d)
+        return "<MarkDecorator {!r} {!r}>".format(name, d)
 
     def __call__(self, *args, **kwargs):
         """ if passed a single callable argument: decorate it with mark info.
@@ -295,7 +295,7 @@ class MarkInfo:
         self._arglist = [(args, kwargs.copy())]
 
     def __repr__(self):
-        return "<MarkInfo %r args=%r kwargs=%r>" % (
+        return "<MarkInfo {!r} args={!r} kwargs={!r}>".format(
             self.name, self.args, self.kwargs
         )
 
diff --git a/python/pytest/_pytest/monkeypatch.py b/python/pytest/_pytest/monkeypatch.py
index d4c169d37a..bbb46c00af 100644
--- a/python/pytest/_pytest/monkeypatch.py
+++ b/python/pytest/_pytest/monkeypatch.py
@@ -56,7 +56,7 @@ def resolve(name):
                 raise
             else:
                 raise ImportError(
-                    'import error in %s: %s' % (used, ex)
+                    'import error in {}: {}'.format(used, ex)
                 )
         found = annotated_getattr(found, part, used)
     return found
@@ -67,7 +67,7 @@ def annotated_getattr(obj, name, ann):
         obj = getattr(obj, name)
     except AttributeError:
         raise AttributeError(
-                '%r object at %s has no attribute %r' % (
+                '{!r} object at {} has no attribute {!r}'.format(
                     type(obj).__name__, ann, name
                 )
         )
@@ -129,7 +129,7 @@ class monkeypatch:
 
         oldval = getattr(target, name, notset)
         if raising and oldval is notset:
-            raise AttributeError("%r has no attribute %r" % (target, name))
+            raise AttributeError("{!r} has no attribute {!r}".format(target, name))
 
         # avoid class descriptors like staticmethod/classmethod
         if inspect.isclass(target):
diff --git a/python/pytest/_pytest/pastebin.py b/python/pytest/_pytest/pastebin.py
index 4ec62d0228..8e103db57e 100644
--- a/python/pytest/_pytest/pastebin.py
+++ b/python/pytest/_pytest/pastebin.py
@@ -53,11 +53,8 @@ def create_new_paste(contents):
     :returns: url to the pasted contents
     """
     import re
-    if sys.version_info < (3, 0):
-        from urllib import urlopen, urlencode
-    else:
-        from urllib.request import urlopen
-        from urllib.parse import urlencode
+    from urllib.request import urlopen
+    from urllib.parse import urlencode
 
     params = {
         'code': contents,
@@ -68,7 +65,7 @@ def create_new_paste(contents):
     response = urlopen(url, data=urlencode(params).encode('ascii')).read()
     m = re.search(r'href="/raw/(\w+)"', response.decode('utf-8'))
     if m:
-        return '%s/show/%s' % (url, m.group(1))
+        return '{}/show/{}'.format(url, m.group(1))
     else:
         return 'bad response: ' + response
 
diff --git a/python/pytest/_pytest/pdb.py b/python/pytest/_pytest/pdb.py
index 84c920d172..256863f0cb 100644
--- a/python/pytest/_pytest/pdb.py
+++ b/python/pytest/_pytest/pdb.py
@@ -1,6 +1,5 @@
 """ interactive debugging with PDB, the Python Debugger. """
-from __future__ import absolute_import
-import pdb
+from . import pdb
 import sys
 
 import pytest
@@ -83,7 +82,7 @@ def _enter_pdb(node, excinfo, rep):
 def _postmortem_traceback(excinfo):
     # A doctest.UnexpectedException is not useful for post_mortem.
     # Use the underlying exception instead:
-    from doctest import UnexpectedException
+    from .doctest import UnexpectedException
     if isinstance(excinfo.value, UnexpectedException):
         return excinfo.value.exc_info[2]
     else:
diff --git a/python/pytest/_pytest/pytester.py b/python/pytest/_pytest/pytester.py
index faed7f581c..5966219e8f 100644
--- a/python/pytest/_pytest/pytester.py
+++ b/python/pytest/_pytest/pytester.py
@@ -1,4 +1,5 @@
 """ (disabled by default) support for testing pytest and pytest plugins. """
+from __future__ import print_function
 import codecs
 import gc
 import os
@@ -45,7 +46,7 @@ def pytest_configure(config):
             config.pluginmanager.register(checker)
 
 
-class LsofFdLeakChecker(object):
+class LsofFdLeakChecker:
     def get_open_files(self):
         out = self._exec_lsof()
         open_files = self._parse_lsof_output(out)
@@ -91,7 +92,7 @@ class LsofFdLeakChecker(object):
             gc.collect()
         lines2 = self.get_open_files()
 
-        new_fds = set([t[0] for t in lines2]) - set([t[0] for t in lines1])
+        new_fds = {t[0] for t in lines2} - {t[0] for t in lines1}
         leaked_files = [t for t in lines2 if t[0] in new_fds]
         if leaked_files:
             error = []
@@ -147,7 +148,7 @@ def anypython(request):
                 executable = py.path.local(executable)
                 if executable.check():
                     return executable
-        pytest.skip("no suitable %s found" % (name,))
+        pytest.skip("no suitable {} found".format(name))
     return executable
 
 # used at least by pytest-xdist plugin
@@ -232,7 +233,7 @@ class HookRecorder:
                     break
                 print_("NONAMEMATCH", name, "with", call)
             else:
-                pytest.fail("could not find %r check %r" % (name, check))
+                pytest.fail("could not find {!r} check {!r}".format(name, check))
 
     def popcall(self, name):
         __tracebackhide__ = True
@@ -240,7 +241,7 @@ class HookRecorder:
             if call._name == name:
                 del self.calls[i]
                 return call
-        lines = ["could not find call %r, in:" % (name,)]
+        lines = ["could not find call {!r}, in:".format(name)]
         lines.extend(["  %s" % str(x) for x in self.calls])
         pytest.fail("\n".join(lines))
 
@@ -327,7 +328,7 @@ def testdir(request, tmpdir_factory):
     return Testdir(request, tmpdir_factory)
 
 
-rex_outcome = re.compile("(\d+) ([\w-]+)")
+rex_outcome = re.compile(r"(\d+) ([\w-]+)")
 class RunResult:
     """The result of running a command.
 
@@ -418,7 +419,7 @@ class Testdir:
             self._runpytest_method = self.runpytest_subprocess
 
     def __repr__(self):
-        return "<Testdir %r>" % (self.tmpdir,)
+        return "<Testdir {!r}>".format(self.tmpdir)
 
     def finalize(self):
         """Clean up global state artifacts.
@@ -870,8 +871,8 @@ class Testdir:
 
         """
         env = os.environ.copy()
-        env['PYTHONPATH'] = os.pathsep.join(filter(None, [
-            str(os.getcwd()), env.get('PYTHONPATH', '')]))
+        env['PYTHONPATH'] = os.pathsep.join([_f for _f in [
+            str(os.getcwd()), env.get('PYTHONPATH', '')] if _f])
         kw['env'] = env
         return subprocess.Popen(cmdargs,
                                 stdout=stdout, stderr=stderr, **kw)
@@ -920,7 +921,7 @@ class Testdir:
             for line in lines:
                 py.builtin.print_(line, file=fp)
         except UnicodeEncodeError:
-            print("couldn't print to %s because of encoding" % (fp,))
+            print(("couldn't print to {} because of encoding".format(fp)))
 
     def _getpytestargs(self):
         # we cannot use "(sys.executable,script)"
@@ -977,7 +978,7 @@ class Testdir:
         """
         basetemp = self.tmpdir.mkdir("pexpect")
         invoke = " ".join(map(str, self._getpytestargs()))
-        cmd = "%s --basetemp=%s %s" % (invoke, basetemp, string)
+        cmd = "{} --basetemp={} {}".format(invoke, basetemp, string)
         return self.spawn(cmd, expect_timeout=expect_timeout)
 
     def spawn(self, cmd, expect_timeout=10.0):
@@ -1002,8 +1003,8 @@ def getdecoded(out):
         try:
             return out.decode("utf-8")
         except UnicodeDecodeError:
-            return "INTERNAL not-utf8-decodeable, truncated string:\n%s" % (
-                    py.io.saferepr(out),)
+            return "INTERNAL not-utf8-decodeable, truncated string:\n{}".format(
+                    py.io.saferepr(out))
 
 
 class LineComp:
@@ -1107,4 +1108,4 @@ class LineMatcher:
                     show("    and:", repr(nextline))
                 extralines.append(nextline)
             else:
-                pytest.fail("remains unmatched: %r, see stderr" % (line,))
+                pytest.fail("remains unmatched: {!r}, see stderr".format(line))
diff --git a/python/pytest/_pytest/python.py b/python/pytest/_pytest/python.py
index 21d78aea33..e22dc44a93 100644
--- a/python/pytest/_pytest/python.py
+++ b/python/pytest/_pytest/python.py
@@ -52,7 +52,7 @@ if  sys.version_info[:2] == (2, 6):
         something on __getattr__ calls (see #1035).
         Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc
         """
-        return isinstance(object, (type, types.ClassType))
+        return isinstance(object, (type, type))
 
 def _has_positional_arg(func):
     return func.__code__.co_argcount
@@ -96,7 +96,7 @@ def getimfunc(func):
         return func.__func__
     except AttributeError:
         try:
-            return func.im_func
+            return func.__func__
         except AttributeError:
             return func
 
@@ -188,8 +188,8 @@ def pyobj_property(name):
         node = self.getparent(getattr(pytest, name))
         if node is not None:
             return node.obj
-    doc = "python %s object this node was collected from (can be None)." % (
-          name.lower(),)
+    doc = "python {} object this node was collected from (can be None).".format(
+          name.lower())
     return property(get, None, None, doc)
 
 
@@ -337,7 +337,7 @@ def is_generator(func):
         # assume them to not be generators
         return False
 
-class PyobjContext(object):
+class PyobjContext:
     module = pyobj_property("Module")
     cls = pyobj_property("Class")
     instance = pyobj_property("Instance")
@@ -602,7 +602,7 @@ class Module(pytest.File, PyCollector):
 
     def collect(self):
         self.session._fixturemanager.parsefactories(self)
-        return super(Module, self).collect()
+        return super().collect()
 
     def _importtestmodule(self):
         # we assume we are only called once per module
@@ -683,7 +683,7 @@ class Instance(PyCollector):
 
     def collect(self):
         self.session._fixturemanager.parsefactories(self)
-        return super(Instance, self).collect()
+        return super().collect()
 
     def newinstance(self):
         self.obj = self._getobj()
@@ -741,7 +741,7 @@ class FunctionMixin(PyobjMixin):
         if excinfo.errisinstance(pytest.fail.Exception):
             if not excinfo.value.pytrace:
                 return py._builtin._totext(excinfo.value)
-        return super(FunctionMixin, self)._repr_failure_py(excinfo,
+        return super()._repr_failure_py(excinfo,
             style=style)
 
     def repr_failure(self, excinfo, outerr=None):
@@ -821,7 +821,7 @@ def fillfixtures(function):
 
 _notexists = object()
 
-class CallSpec2(object):
+class CallSpec2:
     def __init__(self, metafunc):
         self.metafunc = metafunc
         self.funcargs = {}
@@ -861,7 +861,7 @@ class CallSpec2(object):
 
     @property
     def id(self):
-        return "-".join(map(str, filter(None, self._idlist)))
+        return "-".join(map(str, [_f for _f in self._idlist if _f]))
 
     def setmulti(self, valtypes, argnames, valset, id, keywords, scopenum,
                  param_index):
@@ -1127,7 +1127,7 @@ def _idval(val, argname, idx, idfn):
         return str(val)
     elif isclass(val) and hasattr(val, '__name__'):
         return val.__name__
-    elif _PY2 and isinstance(val, unicode):
+    elif _PY2 and isinstance(val, str):
         # special case for python 2: if a unicode string is
         # convertible to ascii, return it as an str() object instead
         try:
@@ -1318,9 +1318,9 @@ def raises(expected_exception, *args, **kwargs):
             func(*args[1:], **kwargs)
         except expected_exception:
             return _pytest._code.ExceptionInfo()
-    pytest.fail("DID NOT RAISE {0}".format(expected_exception))
+    pytest.fail("DID NOT RAISE {}".format(expected_exception))
 
-class RaisesContext(object):
+class RaisesContext:
     def __init__(self, expected_exception):
         self.expected_exception = expected_exception
         self.excinfo = None
@@ -1355,7 +1355,7 @@ class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr):
     def __init__(self, name, parent, args=None, config=None,
                  callspec=None, callobj=NOTSET, keywords=None, session=None,
                  fixtureinfo=None):
-        super(Function, self).__init__(name, parent, config=config,
+        super().__init__(name, parent, config=config,
                                        session=session)
         self._args = args
         if callobj is not NOTSET:
@@ -1415,7 +1415,7 @@ class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr):
         self.ihook.pytest_pyfunc_call(pyfuncitem=self)
 
     def setup(self):
-        super(Function, self).setup()
+        super().setup()
         fillfixtures(self)
 
 
@@ -1431,7 +1431,7 @@ def scopeproperty(name=None, doc=None):
         def provide(self):
             if func.__name__ in scope2props[self.scope]:
                 return func(self)
-            raise AttributeError("%s not available in %s-scoped context" % (
+            raise AttributeError("{} not available in {}-scoped context".format(
                 scopename, self.scope))
         return property(provide, None, None, func.__doc__)
     return decoratescope
@@ -1736,7 +1736,7 @@ class SubRequest(FixtureRequest):
         self._fixturemanager = request._fixturemanager
 
     def __repr__(self):
-        return "<SubRequest %r for %r>" % (self.fixturename, self._pyfuncitem)
+        return "<SubRequest {!r} for {!r}>".format(self.fixturename, self._pyfuncitem)
 
 
 class ScopeMismatchError(Exception):
@@ -1762,7 +1762,7 @@ class FixtureLookupError(LookupError):
         tblines = []
         addline = tblines.append
         stack = [self.request._pyfuncitem.obj]
-        stack.extend(map(lambda x: x.func, self.fixturestack))
+        stack.extend([x.func for x in self.fixturestack])
         msg = self.msg
         if msg is not None:
             # the last fixture raise an error, let's present
@@ -1772,11 +1772,11 @@ class FixtureLookupError(LookupError):
             fspath, lineno = getfslineno(function)
             try:
                 lines, _ = inspect.getsourcelines(get_real_func(function))
-            except (IOError, IndexError):
+            except (OSError, IndexError):
                 error_msg = "file %s, line %s: source code not available"
                 addline(error_msg % (fspath, lineno+1))
             else:
-                addline("file %s, line %s" % (fspath, lineno+1))
+                addline("file {}, line {}".format(fspath, lineno+1))
                 for i, line in enumerate(lines):
                     line = line.rstrip()
                     addline("  " + line)
@@ -1791,7 +1791,7 @@ class FixtureLookupError(LookupError):
                 faclist = list(fm._matchfactories(fixturedef, parentid))
                 if faclist:
                     available.append(name)
-            msg = "fixture %r not found" % (self.argname,)
+            msg = "fixture {!r} not found".format(self.argname)
             msg += "\n available fixtures: %s" %(", ".join(available),)
             msg += "\n use 'py.test --fixtures [testpath]' for help on them."
 
@@ -2023,7 +2023,7 @@ class FixtureManager:
 
 def fail_fixturefunc(fixturefunc, msg):
     fs, lineno = getfslineno(fixturefunc)
-    location = "%s:%s" % (fs, lineno+1)
+    location = "{}:{}".format(fs, lineno+1)
     source = _pytest._code.Source(fixturefunc)
     pytest.fail(msg + ":\n\n" + str(source.indent()) + "\n" + location,
                 pytrace=False)
diff --git a/python/pytest/_pytest/recwarn.py b/python/pytest/_pytest/recwarn.py
index a89474c036..6cecb5e8ee 100644
--- a/python/pytest/_pytest/recwarn.py
+++ b/python/pytest/_pytest/recwarn.py
@@ -71,7 +71,7 @@ def deprecated_call(func=None, *args, **kwargs):
     deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
     if not any(issubclass(c, deprecation_categories) for c in categories):
         __tracebackhide__ = True
-        raise AssertionError("%r did not produce DeprecationWarning" % (func,))
+        raise AssertionError("{!r} did not produce DeprecationWarning".format(func))
     return ret
 
 
@@ -110,7 +110,7 @@ def warns(expected_warning, *args, **kwargs):
             return func(*args[1:], **kwargs)
 
 
-class RecordedWarning(object):
+class RecordedWarning:
     def __init__(self, message, category, filename, lineno, file, line):
         self.message = message
         self.category = category
@@ -120,7 +120,7 @@ class RecordedWarning(object):
         self.line = line
 
 
-class WarningsRecorder(object):
+class WarningsRecorder:
     """A context manager to record raised warnings.
 
     Adapted from `warnings.catch_warnings`.
@@ -195,7 +195,7 @@ class WarningsRecorder(object):
 
 class WarningsChecker(WarningsRecorder):
     def __init__(self, expected_warning=None, module=None):
-        super(WarningsChecker, self).__init__(module=module)
+        super().__init__(module=module)
 
         msg = ("exceptions must be old-style classes or "
                "derived from Warning, not %s")
@@ -211,7 +211,7 @@ class WarningsChecker(WarningsRecorder):
         self.expected_warning = expected_warning
 
     def __exit__(self, *exc_info):
-        super(WarningsChecker, self).__exit__(*exc_info)
+        super().__exit__(*exc_info)
 
         # only check if we're not currently handling an exception
         if all(a is None for a in exc_info):
diff --git a/python/pytest/_pytest/resultlog.py b/python/pytest/_pytest/resultlog.py
index 3670f0214c..1d963adba8 100644
--- a/python/pytest/_pytest/resultlog.py
+++ b/python/pytest/_pytest/resultlog.py
@@ -52,13 +52,13 @@ def generic_path(item):
         fspath = newfspath
     return ''.join(gpath)
 
-class ResultLog(object):
+class ResultLog:
     def __init__(self, config, logfile):
         self.config = config
         self.logfile = logfile # preferably line buffered
 
     def write_log_entry(self, testpath, lettercode, longrepr):
-        py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
+        py.builtin.print_("{} {}".format(lettercode, testpath), file=self.logfile)
         for line in longrepr.splitlines():
             py.builtin.print_(" %s" % line, file=self.logfile)
 
diff --git a/python/pytest/_pytest/runner.py b/python/pytest/_pytest/runner.py
index cde94c8c89..d35b3f3232 100644
--- a/python/pytest/_pytest/runner.py
+++ b/python/pytest/_pytest/runner.py
@@ -159,8 +159,8 @@ class CallInfo:
         if self.excinfo:
             status = "exception: %s" % str(self.excinfo.value)
         else:
-            status = "result: %r" % (self.result,)
-        return "<CallInfo when=%r %s>" % (self.when, status)
+            status = "result: {!r}".format(self.result)
+        return "<CallInfo when={!r} {}>".format(self.when, status)
 
 def getslaveinfoline(node):
     try:
@@ -168,11 +168,11 @@ def getslaveinfoline(node):
     except AttributeError:
         d = node.slaveinfo
         ver = "%s.%s.%s" % d['version_info'][:3]
-        node._slaveinfocache = s = "[%s] %s -- Python %s %s" % (
+        node._slaveinfocache = s = "[{}] {} -- Python {} {}".format(
             d['id'], d['sysplatform'], ver, d['executable'])
         return s
 
-class BaseReport(object):
+class BaseReport:
 
     def __init__(self, **kw):
         self.__dict__.update(kw)
@@ -209,7 +209,7 @@ class BaseReport(object):
 def pytest_runtest_makereport(item, call):
     when = call.when
     duration = call.stop-call.start
-    keywords = dict([(x,1) for x in item.keywords])
+    keywords = {x:1 for x in item.keywords}
     excinfo = call.excinfo
     sections = []
     if not call.excinfo:
@@ -273,7 +273,7 @@ class TestReport(BaseReport):
         self.__dict__.update(extra)
 
     def __repr__(self):
-        return "<TestReport %r when=%r outcome=%r>" % (
+        return "<TestReport {!r} when={!r} outcome={!r}>".format(
             self.nodeid, self.when, self.outcome)
 
 class TeardownErrorReport(BaseReport):
@@ -323,7 +323,7 @@ class CollectReport(BaseReport):
         return (self.fspath, None, self.fspath)
 
     def __repr__(self):
-        return "<CollectReport %r lenresult=%s outcome=%r>" % (
+        return "<CollectReport {!r} lenresult={} outcome={!r}>".format(
                 self.nodeid, len(self.result), self.outcome)
 
 class CollectErrorRepr(TerminalRepr):
@@ -332,7 +332,7 @@ class CollectErrorRepr(TerminalRepr):
     def toterminal(self, out):
         out.line(self.longrepr, red=True)
 
-class SetupState(object):
+class SetupState:
     """ shared state for setting up/tearing down test items or collectors. """
     def __init__(self):
         self.stack = []
diff --git a/python/pytest/_pytest/skipping.py b/python/pytest/_pytest/skipping.py
index 18e038d2c8..0ef3cad1b1 100644
--- a/python/pytest/_pytest/skipping.py
+++ b/python/pytest/_pytest/skipping.py
@@ -112,7 +112,7 @@ class MarkEvaluator:
         try:
             d.update(func.__globals__)
         except AttributeError:
-            d.update(func.func_globals)
+            d.update(func.__globals__)
         return d
 
     def _istrue(self):
@@ -307,7 +307,7 @@ def show_xfailed(terminalreporter, lines):
         for rep in xfailed:
             pos = terminalreporter.config.cwd_relative_nodeid(rep.nodeid)
             reason = rep.wasxfail
-            lines.append("XFAIL %s" % (pos,))
+            lines.append("XFAIL {}".format(pos))
             if reason:
                 lines.append("  " + str(reason))
 
diff --git a/python/pytest/_pytest/standalonetemplate.py b/python/pytest/_pytest/standalonetemplate.py
index 484d5d1b25..13e4fcca1d 100755
--- a/python/pytest/_pytest/standalonetemplate.py
+++ b/python/pytest/_pytest/standalonetemplate.py
@@ -26,7 +26,7 @@ import sys
 import base64
 import zlib
 
-class DictImporter(object):
+class DictImporter:
     def __init__(self, sources):
         self.sources = sources
 
@@ -53,7 +53,7 @@ class DictImporter(object):
 
         co = compile(s, fullname, 'exec')
         module = sys.modules.setdefault(fullname, ModuleType(fullname))
-        module.__file__ = "%s/%s" % (__file__, fullname)
+        module.__file__ = "{}/{}".format(__file__, fullname)
         module.__loader__ = self
         if is_pkg:
             module.__path__ = [fullname]
@@ -73,15 +73,10 @@ if __name__ == "__main__":
     except ImportError:
         sys.stderr.write("ERROR: setuptools not installed\n")
         sys.exit(2)
-    if sys.version_info >= (3, 0):
-        exec("def do_exec(co, loc): exec(co, loc)\n")
-        import pickle
-        sources = sources.encode("ascii") # ensure bytes
-        sources = pickle.loads(zlib.decompress(base64.decodebytes(sources)))
-    else:
-        import cPickle as pickle
-        exec("def do_exec(co, loc): exec co in loc\n")
-        sources = pickle.loads(zlib.decompress(base64.decodestring(sources)))
+    exec("def do_exec(co, loc): exec(co, loc)\n")
+    import pickle
+    sources = sources.encode("ascii") # ensure bytes
+    sources = pickle.loads(zlib.decompress(base64.decodebytes(sources)))
 
     importer = DictImporter(sources)
     sys.meta_path.insert(0, importer)
diff --git a/python/pytest/_pytest/terminal.py b/python/pytest/_pytest/terminal.py
index 825f553ef2..113d6dd6b8 100644
--- a/python/pytest/_pytest/terminal.py
+++ b/python/pytest/_pytest/terminal.py
@@ -179,7 +179,7 @@ class TerminalReporter:
 
     def pytest_plugin_registered(self, plugin):
         if self.config.option.traceconfig:
-            msg = "PLUGIN registered: %s" % (plugin,)
+            msg = "PLUGIN registered: {}".format(plugin)
             # XXX this event may happen during setup/teardown time
             #     which unfortunately captures our output here
             #     which garbles our output if we use self.write_line
@@ -281,11 +281,11 @@ class TerminalReporter:
             return
         self.write_sep("=", "test session starts", bold=True)
         verinfo = platform.python_version()
-        msg = "platform %s -- Python %s" % (sys.platform, verinfo)
+        msg = "platform {} -- Python {}".format(sys.platform, verinfo)
         if hasattr(sys, 'pypy_version_info'):
             verinfo = ".".join(map(str, sys.pypy_version_info[:3]))
-            msg += "[pypy-%s-%s]" % (verinfo, sys.pypy_version_info[3])
-        msg += ", pytest-%s, py-%s, pluggy-%s" % (
+            msg += "[pypy-{}-{}]".format(verinfo, sys.pypy_version_info[3])
+        msg += ", pytest-{}, py-{}, pluggy-{}".format(
                pytest.__version__, py.__version__, pluggy.__version__)
         if self.verbosity > 0 or self.config.option.debug or \
            getattr(self.config.option, 'pastebin', None):
@@ -355,7 +355,7 @@ class TerminalReporter:
                 #if col.name == "()":
                 #    continue
                 indent = (len(stack) - 1) * "  "
-                self._tw.line("%s%s" % (indent, col))
+                self._tw.line("{}{}".format(indent, col))
 
     @pytest.hookimpl(hookwrapper=True)
     def pytest_sessionfinish(self, exitstatus):
@@ -447,7 +447,7 @@ class TerminalReporter:
                 return
             self.write_sep("=", "pytest-warning summary")
             for w in warnings:
-                self._tw.line("W%s %s %s" % (w.code,
+                self._tw.line("W{} {} {}".format(w.code,
                               w.fslocation, w.message))
 
     def summary_passes(self):
@@ -507,7 +507,7 @@ class TerminalReporter:
     def summary_stats(self):
         session_duration = time.time() - self._sessionstarttime
         (line, color) = build_summary_stats_line(self.stats)
-        msg = "%s in %.2f seconds" % (line, session_duration)
+        msg = "{} in {:.2f} seconds".format(line, session_duration)
         markup = {color: True, 'bold': True}
 
         if self.verbosity >= 0:
@@ -539,8 +539,7 @@ def repr_pythonversion(v=None):
 def flatten(l):
     for x in l:
         if isinstance(x, (list, tuple)):
-            for y in flatten(x):
-                yield y
+            yield from flatten(x)
         else:
             yield x
 
diff --git a/python/pytest/_pytest/tmpdir.py b/python/pytest/_pytest/tmpdir.py
index ebc48dbe5b..594cd8bbbb 100644
--- a/python/pytest/_pytest/tmpdir.py
+++ b/python/pytest/_pytest/tmpdir.py
@@ -115,7 +115,7 @@ def tmpdir(request, tmpdir_factory):
     path object.
     """
     name = request.node.name
-    name = re.sub("[\W]", "_", name)
+    name = re.sub(r"[\W]", "_", name)
     MAXVAL = 30
     if len(name) > MAXVAL:
         name = name[:MAXVAL]
diff --git a/python/pytest/_pytest/unittest.py b/python/pytest/_pytest/unittest.py
index 8120e94fbf..1880581e75 100644
--- a/python/pytest/_pytest/unittest.py
+++ b/python/pytest/_pytest/unittest.py
@@ -1,5 +1,4 @@
 """ discovery and running of std-library "unittest" style tests. """
-from __future__ import absolute_import
 
 import sys
 import traceback
@@ -37,10 +36,10 @@ class UnitTestCase(pytest.Class):
         teardown = getattr(cls, 'tearDownClass', None)
         if teardown is not None:
             self.addfinalizer(teardown)
-        super(UnitTestCase, self).setup()
+        super().setup()
 
     def collect(self):
-        from unittest import TestLoader
+        from .unittest import TestLoader
         cls = self.obj
         if not getattr(cls, "__test__", True):
             return
diff --git a/python/pytest/_pytest/vendored_packages/pluggy.py b/python/pytest/_pytest/vendored_packages/pluggy.py
index 2f848b23d3..659bad8ec9 100644
--- a/python/pytest/_pytest/vendored_packages/pluggy.py
+++ b/python/pytest/_pytest/vendored_packages/pluggy.py
@@ -186,11 +186,11 @@ class _TagTracer:
         indent = "  " * self.indent
 
         lines = [
-            "%s%s [%s]\n" % (indent, content, ":".join(tags))
+            "{}{} [{}]\n".format(indent, content, ":".join(tags))
         ]
 
         for name, value in extra.items():
-            lines.append("%s    %s: %s\n" % (indent, name, value))
+            lines.append("{}    {}: {}\n".format(indent, name, value))
         return lines
 
     def processmessage(self, tags, args):
@@ -281,7 +281,7 @@ class _CallOutcome:
 if not _py3:
     exec("""
 def _reraise(cls, val, tb):
-    raise cls, val, tb
+    raise cls(val, tb)
 """)
 
 
@@ -304,7 +304,7 @@ class _TracedHookExecution:
         self.pluginmanager._inner_hookexec = self.oldcall
 
 
-class PluginManager(object):
+class PluginManager:
     """ Core Pluginmanager class which manages registration
     of plugin objects and 1:N hook calling.
 
@@ -606,7 +606,7 @@ class _MultiCall:
         status = "%d meths" % (len(self.hook_impls),)
         if hasattr(self, "results"):
             status = ("%d results, " % len(self.results)) + status
-        return "<_MultiCall %s, kwargs=%r>" % (status, self.kwargs)
+        return "<_MultiCall {}, kwargs={!r}>".format(status, self.kwargs)
 
 
 def varnames(func, startindex=None):
@@ -662,7 +662,7 @@ class _HookRelay:
         self._trace = trace
 
 
-class _HookCaller(object):
+class _HookCaller:
     def __init__(self, name, hook_execute, specmodule_or_class=None, spec_opts=None):
         self.name = name
         self._wrappers = []
@@ -697,7 +697,7 @@ class _HookCaller(object):
                     return True
         if remove(self._wrappers) is None:
             if remove(self._nonwrappers) is None:
-                raise ValueError("plugin %r not found" % (plugin,))
+                raise ValueError("plugin {!r} not found".format(plugin))
 
     def _add_hookimpl(self, hookimpl):
         if hookimpl.hookwrapper:
@@ -717,7 +717,7 @@ class _HookCaller(object):
             methods.insert(i + 1, hookimpl)
 
     def __repr__(self):
-        return "<_HookCaller %r>" % (self.name,)
+        return "<_HookCaller {!r}>".format(self.name)
 
     def __call__(self, **kwargs):
         assert not self.is_historic()
@@ -765,13 +765,13 @@ class PluginValidationError(Exception):
 
 if hasattr(inspect, 'signature'):
     def _formatdef(func):
-        return "%s%s" % (
+        return "{}{}".format(
             func.__name__,
             str(inspect.signature(func))
         )
 else:
     def _formatdef(func):
-        return "%s%s" % (
+        return "{}{}".format(
             func.__name__,
             inspect.formatargspec(*inspect.getargspec(func))
         )
diff --git a/python/pytest/setup.py b/python/pytest/setup.py
index 7cdcdfb992..af5b95228d 100644
--- a/python/pytest/setup.py
+++ b/python/pytest/setup.py
@@ -99,7 +99,7 @@ def make_entry_points():
     points = cmdline_entrypoints(sys.version_info, sys.platform, basename)
     keys = list(points.keys())
     keys.sort()
-    l = ['%s = %s' % (x, points[x]) for x in keys]
+    l = ['{} = {}'.format(x, points[x]) for x in keys]
     return {'console_scripts': l}
 
 
diff --git a/python/pyyaml/examples/pygments-lexer/yaml.py b/python/pyyaml/examples/pygments-lexer/yaml.py
index 1ce9dac9e4..a2c91febda 100644
--- a/python/pyyaml/examples/pygments-lexer/yaml.py
+++ b/python/pyyaml/examples/pygments-lexer/yaml.py
@@ -1,4 +1,3 @@
-
 """
 yaml.py
 
@@ -22,7 +21,7 @@ class YAMLLexerContext(LexerContext):
     """Indentation context for the YAML lexer."""
 
     def __init__(self, *args, **kwds):
-        super(YAMLLexerContext, self).__init__(*args, **kwds)
+        super().__init__(*args, **kwds)
         self.indent_stack = []
         self.indent = -1
         self.next_indent = 0
@@ -426,6 +425,6 @@ class YAMLLexer(ExtendedRegexLexer):
     def get_tokens_unprocessed(self, text=None, context=None):
         if context is None:
             context = YAMLLexerContext(text, 0)
-        return super(YAMLLexer, self).get_tokens_unprocessed(text, context)
+        return super().get_tokens_unprocessed(text, context)
 
 
diff --git a/python/pyyaml/examples/yaml-highlight/yaml_hl.py b/python/pyyaml/examples/yaml-highlight/yaml_hl.py
index d6f7bf4eb2..8bc6520998 100755
--- a/python/pyyaml/examples/yaml-highlight/yaml_hl.py
+++ b/python/pyyaml/examples/yaml-highlight/yaml_hl.py
@@ -15,7 +15,7 @@ class Style:
                 continue
             for key in domain:
                 name = ''.join([part.capitalize() for part in key.split('-')])
-                cls = getattr(yaml, '%s%s' % (name, Class))
+                cls = getattr(yaml, '{}{}'.format(name, Class))
                 value = domain[key]
                 if not value:
                     continue
@@ -29,33 +29,33 @@ class Style:
     def __setstate__(self, state):
         self.__init__(**state)
 
-yaml.add_path_resolver(u'tag:yaml.org,2002:python/object:__main__.Style',
+yaml.add_path_resolver('tag:yaml.org,2002:python/object:__main__.Style',
         [None], dict)
-yaml.add_path_resolver(u'tag:yaml.org,2002:pairs',
-        [None, u'replaces'], list)
+yaml.add_path_resolver('tag:yaml.org,2002:pairs',
+        [None, 'replaces'], list)
 
 class YAMLHighlight:
 
     def __init__(self, options):
-        config = yaml.load(file(options.config, 'rb').read())
+        config = yaml.load(open(options.config, 'rb').read())
         self.style = config[options.style]
         if options.input:
-            self.input = file(options.input, 'rb')
+            self.input = open(options.input, 'rb')
         else:
             self.input = sys.stdin
         if options.output:
-            self.output = file(options.output, 'wb')
+            self.output = open(options.output, 'wb')
         else:
             self.output = sys.stdout
 
     def highlight(self):
         input = self.input.read()
         if input.startswith(codecs.BOM_UTF16_LE):
-            input = unicode(input, 'utf-16-le')
+            input = str(input, 'utf-16-le')
         elif input.startswith(codecs.BOM_UTF16_BE):
-            input = unicode(input, 'utf-16-be')
+            input = str(input, 'utf-16-be')
         else:
-            input = unicode(input, 'utf-8')
+            input = str(input, 'utf-8')
         substitutions = self.style.substitutions
         tokens = yaml.scan(input)
         events = yaml.parse(input)
@@ -90,7 +90,7 @@ class YAMLHighlight:
                 position = index
             chunks.append(substitution)
         chunks.reverse()
-        result = u''.join(chunks)
+        result = ''.join(chunks)
         if self.style.header:
             self.output.write(self.style.header)
         self.output.write(result.encode('utf-8'))
diff --git a/python/pyyaml/lib/yaml/__init__.py b/python/pyyaml/lib/yaml/__init__.py
index 76e19e13f1..8420f0ac1b 100644
--- a/python/pyyaml/lib/yaml/__init__.py
+++ b/python/pyyaml/lib/yaml/__init__.py
@@ -1,17 +1,17 @@
+from .error import *
 
-from error import *
+from .tokens import *
+from .events import *
+from .nodes import *
 
-from tokens import *
-from events import *
-from nodes import *
-
-from loader import *
-from dumper import *
+from .loader import *
+from .dumper import *
+import six
 
 __version__ = '3.11'
 
 try:
-    from cyaml import *
+    from .cyaml import *
     __with_libyaml__ = True
 except ImportError:
     __with_libyaml__ = False
@@ -278,18 +278,16 @@ class YAMLObjectMetaclass(type):
     The metaclass for YAMLObject.
     """
     def __init__(cls, name, bases, kwds):
-        super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
+        super().__init__(name, bases, kwds)
         if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
             cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
             cls.yaml_dumper.add_representer(cls, cls.to_yaml)
 
-class YAMLObject(object):
+class YAMLObject(six.with_metaclass(YAMLObjectMetaclass)):
     """
     An object that can dump itself to a YAML stream
     and load itself from a YAML stream.
     """
-
-    __metaclass__ = YAMLObjectMetaclass
     __slots__ = ()  # no direct instantiation, so allow immutable subclasses
 
     yaml_loader = Loader
diff --git a/python/pyyaml/lib/yaml/composer.py b/python/pyyaml/lib/yaml/composer.py
index 06e5ac782f..1cc6224505 100644
--- a/python/pyyaml/lib/yaml/composer.py
+++ b/python/pyyaml/lib/yaml/composer.py
@@ -1,14 +1,13 @@
-
 __all__ = ['Composer', 'ComposerError']
 
-from error import MarkedYAMLError
-from events import *
-from nodes import *
+from .error import MarkedYAMLError
+from .events import *
+from .nodes import *
 
 class ComposerError(MarkedYAMLError):
     pass
 
-class Composer(object):
+class Composer:
 
     def __init__(self):
         self.anchors = {}
@@ -88,7 +87,7 @@ class Composer(object):
     def compose_scalar_node(self, anchor):
         event = self.get_event()
         tag = event.tag
-        if tag is None or tag == u'!':
+        if tag is None or tag == '!':
             tag = self.resolve(ScalarNode, event.value, event.implicit)
         node = ScalarNode(tag, event.value,
                 event.start_mark, event.end_mark, style=event.style)
@@ -99,7 +98,7 @@ class Composer(object):
     def compose_sequence_node(self, anchor):
         start_event = self.get_event()
         tag = start_event.tag
-        if tag is None or tag == u'!':
+        if tag is None or tag == '!':
             tag = self.resolve(SequenceNode, None, start_event.implicit)
         node = SequenceNode(tag, [],
                 start_event.start_mark, None,
@@ -117,7 +116,7 @@ class Composer(object):
     def compose_mapping_node(self, anchor):
         start_event = self.get_event()
         tag = start_event.tag
-        if tag is None or tag == u'!':
+        if tag is None or tag == '!':
             tag = self.resolve(MappingNode, None, start_event.implicit)
         node = MappingNode(tag, [],
                 start_event.start_mark, None,
diff --git a/python/pyyaml/lib/yaml/constructor.py b/python/pyyaml/lib/yaml/constructor.py
index 635faac3e6..f689747678 100644
--- a/python/pyyaml/lib/yaml/constructor.py
+++ b/python/pyyaml/lib/yaml/constructor.py
@@ -1,9 +1,8 @@
-
 __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
     'ConstructorError']
 
-from error import *
-from nodes import *
+from .error import *
+from .nodes import *
 
 import datetime
 
@@ -90,7 +89,7 @@ class BaseConstructor(object):
             data = constructor(self, tag_suffix, node)
         if isinstance(data, types.GeneratorType):
             generator = data
-            data = generator.next()
+            data = next(generator)
             if self.deep_construct:
                 for dummy in generator:
                     pass
@@ -127,7 +126,7 @@ class BaseConstructor(object):
             key = self.construct_object(key_node, deep=deep)
             try:
                 hash(key)
-            except TypeError, exc:
+            except TypeError as exc:
                 raise ConstructorError("while constructing a mapping", node.start_mark,
                         "found unacceptable key (%s)" % exc, key_node.start_mark)
             value = self.construct_object(value_node, deep=deep)
@@ -163,7 +162,7 @@ class SafeConstructor(BaseConstructor):
     def construct_scalar(self, node):
         if isinstance(node, MappingNode):
             for key_node, value_node in node.value:
-                if key_node.tag == u'tag:yaml.org,2002:value':
+                if key_node.tag == 'tag:yaml.org,2002:value':
                     return self.construct_scalar(value_node)
         return BaseConstructor.construct_scalar(self, node)
 
@@ -172,7 +171,7 @@ class SafeConstructor(BaseConstructor):
         index = 0
         while index < len(node.value):
             key_node, value_node = node.value[index]
-            if key_node.tag == u'tag:yaml.org,2002:merge':
+            if key_node.tag == 'tag:yaml.org,2002:merge':
                 del node.value[index]
                 if isinstance(value_node, MappingNode):
                     self.flatten_mapping(value_node)
@@ -194,8 +193,8 @@ class SafeConstructor(BaseConstructor):
                     raise ConstructorError("while constructing a mapping", node.start_mark,
                             "expected a mapping or list of mappings for merging, but found %s"
                             % value_node.id, value_node.start_mark)
-            elif key_node.tag == u'tag:yaml.org,2002:value':
-                key_node.tag = u'tag:yaml.org,2002:str'
+            elif key_node.tag == 'tag:yaml.org,2002:value':
+                key_node.tag = 'tag:yaml.org,2002:str'
                 index += 1
             else:
                 index += 1
@@ -212,12 +211,12 @@ class SafeConstructor(BaseConstructor):
         return None
 
     bool_values = {
-        u'yes':     True,
-        u'no':      False,
-        u'true':    True,
-        u'false':   False,
-        u'on':      True,
-        u'off':     False,
+        'yes':     True,
+        'no':      False,
+        'true':    True,
+        'false':   False,
+        'on':      True,
+        'off':     False,
     }
 
     def construct_yaml_bool(self, node):
@@ -285,19 +284,19 @@ class SafeConstructor(BaseConstructor):
         value = self.construct_scalar(node)
         try:
             return str(value).decode('base64')
-        except (binascii.Error, UnicodeEncodeError), exc:
+        except (binascii.Error, UnicodeEncodeError) as exc:
             raise ConstructorError(None, None,
                     "failed to decode base64 data: %s" % exc, node.start_mark) 
 
     timestamp_regexp = re.compile(
-            ur'''^(?P<year>[0-9][0-9][0-9][0-9])
+            r'''^(?P<year>[0-9][0-9][0-9][0-9])
                 -(?P<month>[0-9][0-9]?)
                 -(?P<day>[0-9][0-9]?)
                 (?:(?:[Tt]|[ \t]+)
                 (?P<hour>[0-9][0-9]?)
                 :(?P<minute>[0-9][0-9])
                 :(?P<second>[0-9][0-9])
-                (?:\.(?P<fraction>[0-9]*))?
+                (?:\\.(?P<fraction>[0-9]*))?
                 (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
                 (?::(?P<tz_minute>[0-9][0-9]))?))?)?$''', re.X)
 
@@ -414,51 +413,51 @@ class SafeConstructor(BaseConstructor):
                 node.start_mark)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:null',
+        'tag:yaml.org,2002:null',
         SafeConstructor.construct_yaml_null)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:bool',
+        'tag:yaml.org,2002:bool',
         SafeConstructor.construct_yaml_bool)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:int',
+        'tag:yaml.org,2002:int',
         SafeConstructor.construct_yaml_int)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:float',
+        'tag:yaml.org,2002:float',
         SafeConstructor.construct_yaml_float)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:binary',
+        'tag:yaml.org,2002:binary',
         SafeConstructor.construct_yaml_binary)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:timestamp',
+        'tag:yaml.org,2002:timestamp',
         SafeConstructor.construct_yaml_timestamp)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:omap',
+        'tag:yaml.org,2002:omap',
         SafeConstructor.construct_yaml_omap)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:pairs',
+        'tag:yaml.org,2002:pairs',
         SafeConstructor.construct_yaml_pairs)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:set',
+        'tag:yaml.org,2002:set',
         SafeConstructor.construct_yaml_set)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:str',
+        'tag:yaml.org,2002:str',
         SafeConstructor.construct_yaml_str)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:seq',
+        'tag:yaml.org,2002:seq',
         SafeConstructor.construct_yaml_seq)
 
 SafeConstructor.add_constructor(
-        u'tag:yaml.org,2002:map',
+        'tag:yaml.org,2002:map',
         SafeConstructor.construct_yaml_map)
 
 SafeConstructor.add_constructor(None,
@@ -473,7 +472,7 @@ class Constructor(SafeConstructor):
         return self.construct_scalar(node)
 
     def construct_python_long(self, node):
-        return long(self.construct_yaml_int(node))
+        return int(self.construct_yaml_int(node))
 
     def construct_python_complex(self, node):
        return complex(self.construct_scalar(node))
@@ -487,7 +486,7 @@ class Constructor(SafeConstructor):
                     "expected non-empty name appended to the tag", mark)
         try:
             __import__(name)
-        except ImportError, exc:
+        except ImportError as exc:
             raise ConstructorError("while constructing a Python module", mark,
                     "cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
         return sys.modules[name]
@@ -496,14 +495,14 @@ class Constructor(SafeConstructor):
         if not name:
             raise ConstructorError("while constructing a Python object", mark,
                     "expected non-empty name appended to the tag", mark)
-        if u'.' in name:
+        if '.' in name:
             module_name, object_name = name.rsplit('.', 1)
         else:
             module_name = '__builtin__'
             object_name = name
         try:
             __import__(module_name)
-        except ImportError, exc:
+        except ImportError as exc:
             raise ConstructorError("while constructing a Python object", mark,
                     "cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
         module = sys.modules[module_name]
@@ -610,66 +609,66 @@ class Constructor(SafeConstructor):
         return self.construct_python_object_apply(suffix, node, newobj=True)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/none',
+    'tag:yaml.org,2002:python/none',
     Constructor.construct_yaml_null)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/bool',
+    'tag:yaml.org,2002:python/bool',
     Constructor.construct_yaml_bool)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/str',
+    'tag:yaml.org,2002:python/str',
     Constructor.construct_python_str)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/unicode',
+    'tag:yaml.org,2002:python/unicode',
     Constructor.construct_python_unicode)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/int',
+    'tag:yaml.org,2002:python/int',
     Constructor.construct_yaml_int)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/long',
+    'tag:yaml.org,2002:python/long',
     Constructor.construct_python_long)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/float',
+    'tag:yaml.org,2002:python/float',
     Constructor.construct_yaml_float)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/complex',
+    'tag:yaml.org,2002:python/complex',
     Constructor.construct_python_complex)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/list',
+    'tag:yaml.org,2002:python/list',
     Constructor.construct_yaml_seq)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/tuple',
+    'tag:yaml.org,2002:python/tuple',
     Constructor.construct_python_tuple)
 
 Constructor.add_constructor(
-    u'tag:yaml.org,2002:python/dict',
+    'tag:yaml.org,2002:python/dict',
     Constructor.construct_yaml_map)
 
 Constructor.add_multi_constructor(
-    u'tag:yaml.org,2002:python/name:',
+    'tag:yaml.org,2002:python/name:',
     Constructor.construct_python_name)
 
 Constructor.add_multi_constructor(
-    u'tag:yaml.org,2002:python/module:',
+    'tag:yaml.org,2002:python/module:',
     Constructor.construct_python_module)
 
 Constructor.add_multi_constructor(
-    u'tag:yaml.org,2002:python/object:',
+    'tag:yaml.org,2002:python/object:',
     Constructor.construct_python_object)
 
 Constructor.add_multi_constructor(
-    u'tag:yaml.org,2002:python/object/apply:',
+    'tag:yaml.org,2002:python/object/apply:',
     Constructor.construct_python_object_apply)
 
 Constructor.add_multi_constructor(
-    u'tag:yaml.org,2002:python/object/new:',
+    'tag:yaml.org,2002:python/object/new:',
     Constructor.construct_python_object_new)
 
diff --git a/python/pyyaml/lib/yaml/cyaml.py b/python/pyyaml/lib/yaml/cyaml.py
index 68dcd75192..0baa920d40 100644
--- a/python/pyyaml/lib/yaml/cyaml.py
+++ b/python/pyyaml/lib/yaml/cyaml.py
@@ -1,15 +1,14 @@
-
 __all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
         'CBaseDumper', 'CSafeDumper', 'CDumper']
 
 from _yaml import CParser, CEmitter
 
-from constructor import *
+from .constructor import *
 
-from serializer import *
-from representer import *
+from .serializer import *
+from .representer import *
 
-from resolver import *
+from .resolver import *
 
 class CBaseLoader(CParser, BaseConstructor, BaseResolver):
 
diff --git a/python/pyyaml/lib/yaml/dumper.py b/python/pyyaml/lib/yaml/dumper.py
index f811d2c919..dfd8c7cf36 100644
--- a/python/pyyaml/lib/yaml/dumper.py
+++ b/python/pyyaml/lib/yaml/dumper.py
@@ -1,10 +1,9 @@
-
 __all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
 
-from emitter import *
-from serializer import *
-from representer import *
-from resolver import *
+from .emitter import *
+from .serializer import *
+from .representer import *
+from .resolver import *
 
 class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver):
 
diff --git a/python/pyyaml/lib/yaml/emitter.py b/python/pyyaml/lib/yaml/emitter.py
index e5bcdcccbb..4e5c244850 100644
--- a/python/pyyaml/lib/yaml/emitter.py
+++ b/python/pyyaml/lib/yaml/emitter.py
@@ -1,4 +1,3 @@
-
 # Emitter expects events obeying the following grammar:
 # stream ::= STREAM-START document* STREAM-END
 # document ::= DOCUMENT-START node DOCUMENT-END
@@ -8,13 +7,13 @@
 
 __all__ = ['Emitter', 'EmitterError']
 
-from error import YAMLError
-from events import *
+from .error import YAMLError
+from .events import *
 
 class EmitterError(YAMLError):
     pass
 
-class ScalarAnalysis(object):
+class ScalarAnalysis:
     def __init__(self, scalar, empty, multiline,
             allow_flow_plain, allow_block_plain,
             allow_single_quoted, allow_double_quoted,
@@ -28,11 +27,11 @@ class ScalarAnalysis(object):
         self.allow_double_quoted = allow_double_quoted
         self.allow_block = allow_block
 
-class Emitter(object):
+class Emitter:
 
     DEFAULT_TAG_PREFIXES = {
-        u'!' : u'!',
-        u'tag:yaml.org,2002:' : u'!!',
+        '!' : '!',
+        'tag:yaml.org,2002:' : '!!',
     }
 
     def __init__(self, stream, canonical=None, indent=None, width=None,
@@ -88,8 +87,8 @@ class Emitter(object):
         self.best_width = 80
         if width and width > self.best_indent*2:
             self.best_width = width
-        self.best_line_break = u'\n'
-        if line_break in [u'\r', u'\n', u'\r\n']:
+        self.best_line_break = '\n'
+        if line_break in ['\r', '\n', '\r\n']:
             self.best_line_break = line_break
 
         # Tag prefixes.
@@ -178,14 +177,14 @@ class Emitter(object):
     def expect_document_start(self, first=False):
         if isinstance(self.event, DocumentStartEvent):
             if (self.event.version or self.event.tags) and self.open_ended:
-                self.write_indicator(u'...', True)
+                self.write_indicator('...', True)
                 self.write_indent()
             if self.event.version:
                 version_text = self.prepare_version(self.event.version)
                 self.write_version_directive(version_text)
             self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy()
             if self.event.tags:
-                handles = self.event.tags.keys()
+                handles = list(self.event.tags.keys())
                 handles.sort()
                 for handle in handles:
                     prefix = self.event.tags[handle]
@@ -198,13 +197,13 @@ class Emitter(object):
                     and not self.check_empty_document())
             if not implicit:
                 self.write_indent()
-                self.write_indicator(u'---', True)
+                self.write_indicator('---', True)
                 if self.canonical:
                     self.write_indent()
             self.state = self.expect_document_root
         elif isinstance(self.event, StreamEndEvent):
             if self.open_ended:
-                self.write_indicator(u'...', True)
+                self.write_indicator('...', True)
                 self.write_indent()
             self.write_stream_end()
             self.state = self.expect_nothing
@@ -216,7 +215,7 @@ class Emitter(object):
         if isinstance(self.event, DocumentEndEvent):
             self.write_indent()
             if self.event.explicit:
-                self.write_indicator(u'...', True)
+                self.write_indicator('...', True)
                 self.write_indent()
             self.flush_stream()
             self.state = self.expect_document_start
@@ -239,7 +238,7 @@ class Emitter(object):
         if isinstance(self.event, AliasEvent):
             self.expect_alias()
         elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)):
-            self.process_anchor(u'&')
+            self.process_anchor('&')
             self.process_tag()
             if isinstance(self.event, ScalarEvent):
                 self.expect_scalar()
@@ -261,7 +260,7 @@ class Emitter(object):
     def expect_alias(self):
         if self.event.anchor is None:
             raise EmitterError("anchor is not specified for alias")
-        self.process_anchor(u'*')
+        self.process_anchor('*')
         self.state = self.states.pop()
 
     def expect_scalar(self):
@@ -273,7 +272,7 @@ class Emitter(object):
     # Flow sequence handlers.
 
     def expect_flow_sequence(self):
-        self.write_indicator(u'[', True, whitespace=True)
+        self.write_indicator('[', True, whitespace=True)
         self.flow_level += 1
         self.increase_indent(flow=True)
         self.state = self.expect_first_flow_sequence_item
@@ -282,7 +281,7 @@ class Emitter(object):
         if isinstance(self.event, SequenceEndEvent):
             self.indent = self.indents.pop()
             self.flow_level -= 1
-            self.write_indicator(u']', False)
+            self.write_indicator(']', False)
             self.state = self.states.pop()
         else:
             if self.canonical or self.column > self.best_width:
@@ -295,12 +294,12 @@ class Emitter(object):
             self.indent = self.indents.pop()
             self.flow_level -= 1
             if self.canonical:
-                self.write_indicator(u',', False)
+                self.write_indicator(',', False)
                 self.write_indent()
-            self.write_indicator(u']', False)
+            self.write_indicator(']', False)
             self.state = self.states.pop()
         else:
-            self.write_indicator(u',', False)
+            self.write_indicator(',', False)
             if self.canonical or self.column > self.best_width:
                 self.write_indent()
             self.states.append(self.expect_flow_sequence_item)
@@ -309,7 +308,7 @@ class Emitter(object):
     # Flow mapping handlers.
 
     def expect_flow_mapping(self):
-        self.write_indicator(u'{', True, whitespace=True)
+        self.write_indicator('{', True, whitespace=True)
         self.flow_level += 1
         self.increase_indent(flow=True)
         self.state = self.expect_first_flow_mapping_key
@@ -318,7 +317,7 @@ class Emitter(object):
         if isinstance(self.event, MappingEndEvent):
             self.indent = self.indents.pop()
             self.flow_level -= 1
-            self.write_indicator(u'}', False)
+            self.write_indicator('}', False)
             self.state = self.states.pop()
         else:
             if self.canonical or self.column > self.best_width:
@@ -327,7 +326,7 @@ class Emitter(object):
                 self.states.append(self.expect_flow_mapping_simple_value)
                 self.expect_node(mapping=True, simple_key=True)
             else:
-                self.write_indicator(u'?', True)
+                self.write_indicator('?', True)
                 self.states.append(self.expect_flow_mapping_value)
                 self.expect_node(mapping=True)
 
@@ -336,31 +335,31 @@ class Emitter(object):
             self.indent = self.indents.pop()
             self.flow_level -= 1
             if self.canonical:
-                self.write_indicator(u',', False)
+                self.write_indicator(',', False)
                 self.write_indent()
-            self.write_indicator(u'}', False)
+            self.write_indicator('}', False)
             self.state = self.states.pop()
         else:
-            self.write_indicator(u',', False)
+            self.write_indicator(',', False)
             if self.canonical or self.column > self.best_width:
                 self.write_indent()
             if not self.canonical and self.check_simple_key():
                 self.states.append(self.expect_flow_mapping_simple_value)
                 self.expect_node(mapping=True, simple_key=True)
             else:
-                self.write_indicator(u'?', True)
+                self.write_indicator('?', True)
                 self.states.append(self.expect_flow_mapping_value)
                 self.expect_node(mapping=True)
 
     def expect_flow_mapping_simple_value(self):
-        self.write_indicator(u':', False)
+        self.write_indicator(':', False)
         self.states.append(self.expect_flow_mapping_key)
         self.expect_node(mapping=True)
 
     def expect_flow_mapping_value(self):
         if self.canonical or self.column > self.best_width:
             self.write_indent()
-        self.write_indicator(u':', True)
+        self.write_indicator(':', True)
         self.states.append(self.expect_flow_mapping_key)
         self.expect_node(mapping=True)
 
@@ -380,7 +379,7 @@ class Emitter(object):
             self.state = self.states.pop()
         else:
             self.write_indent()
-            self.write_indicator(u'-', True, indention=True)
+            self.write_indicator('-', True, indention=True)
             self.states.append(self.expect_block_sequence_item)
             self.expect_node(sequence=True)
 
@@ -403,18 +402,18 @@ class Emitter(object):
                 self.states.append(self.expect_block_mapping_simple_value)
                 self.expect_node(mapping=True, simple_key=True)
             else:
-                self.write_indicator(u'?', True, indention=True)
+                self.write_indicator('?', True, indention=True)
                 self.states.append(self.expect_block_mapping_value)
                 self.expect_node(mapping=True)
 
     def expect_block_mapping_simple_value(self):
-        self.write_indicator(u':', False)
+        self.write_indicator(':', False)
         self.states.append(self.expect_block_mapping_key)
         self.expect_node(mapping=True)
 
     def expect_block_mapping_value(self):
         self.write_indent()
-        self.write_indicator(u':', True, indention=True)
+        self.write_indicator(':', True, indention=True)
         self.states.append(self.expect_block_mapping_key)
         self.expect_node(mapping=True)
 
@@ -433,7 +432,7 @@ class Emitter(object):
             return False
         event = self.events[0]
         return (isinstance(event, ScalarEvent) and event.anchor is None
-                and event.tag is None and event.implicit and event.value == u'')
+                and event.tag is None and event.implicit and event.value == '')
 
     def check_simple_key(self):
         length = 0
@@ -478,7 +477,7 @@ class Emitter(object):
                 self.prepared_tag = None
                 return
             if self.event.implicit[0] and tag is None:
-                tag = u'!'
+                tag = '!'
                 self.prepared_tag = None
         else:
             if (not self.canonical or tag is None) and self.event.implicit:
@@ -541,17 +540,17 @@ class Emitter(object):
         major, minor = version
         if major != 1:
             raise EmitterError("unsupported YAML version: %d.%d" % (major, minor))
-        return u'%d.%d' % (major, minor)
+        return '%d.%d' % (major, minor)
 
     def prepare_tag_handle(self, handle):
         if not handle:
             raise EmitterError("tag handle must not be empty")
-        if handle[0] != u'!' or handle[-1] != u'!':
+        if handle[0] != '!' or handle[-1] != '!':
             raise EmitterError("tag handle must start and end with '!': %r"
                     % (handle.encode('utf-8')))
         for ch in handle[1:-1]:
-            if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'  \
-                    or ch in u'-_'):
+            if not ('0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'  \
+                    or ch in '-_'):
                 raise EmitterError("invalid character %r in the tag handle: %r"
                         % (ch.encode('utf-8'), handle.encode('utf-8')))
         return handle
@@ -561,12 +560,12 @@ class Emitter(object):
             raise EmitterError("tag prefix must not be empty")
         chunks = []
         start = end = 0
-        if prefix[0] == u'!':
+        if prefix[0] == '!':
             end = 1
         while end < len(prefix):
             ch = prefix[end]
-            if u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'   \
-                    or ch in u'-;/?!:@&=+$,_.~*\'()[]':
+            if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'   \
+                    or ch in '-;/?!:@&=+$,_.~*\'()[]':
                 end += 1
             else:
                 if start < end:
@@ -574,32 +573,32 @@ class Emitter(object):
                 start = end = end+1
                 data = ch.encode('utf-8')
                 for ch in data:
-                    chunks.append(u'%%%02X' % ord(ch))
+                    chunks.append('%%%02X' % ord(ch))
         if start < end:
             chunks.append(prefix[start:end])
-        return u''.join(chunks)
+        return ''.join(chunks)
 
     def prepare_tag(self, tag):
         if not tag:
             raise EmitterError("tag must not be empty")
-        if tag == u'!':
+        if tag == '!':
             return tag
         handle = None
         suffix = tag
-        prefixes = self.tag_prefixes.keys()
+        prefixes = list(self.tag_prefixes.keys())
         prefixes.sort()
         for prefix in prefixes:
             if tag.startswith(prefix)   \
-                    and (prefix == u'!' or len(prefix) < len(tag)):
+                    and (prefix == '!' or len(prefix) < len(tag)):
                 handle = self.tag_prefixes[prefix]
                 suffix = tag[len(prefix):]
         chunks = []
         start = end = 0
         while end < len(suffix):
             ch = suffix[end]
-            if u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'   \
-                    or ch in u'-;/?:@&=+$,_.~*\'()[]'   \
-                    or (ch == u'!' and handle != u'!'):
+            if '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'   \
+                    or ch in '-;/?:@&=+$,_.~*\'()[]'   \
+                    or (ch == '!' and handle != '!'):
                 end += 1
             else:
                 if start < end:
@@ -607,21 +606,21 @@ class Emitter(object):
                 start = end = end+1
                 data = ch.encode('utf-8')
                 for ch in data:
-                    chunks.append(u'%%%02X' % ord(ch))
+                    chunks.append('%%%02X' % ord(ch))
         if start < end:
             chunks.append(suffix[start:end])
-        suffix_text = u''.join(chunks)
+        suffix_text = ''.join(chunks)
         if handle:
-            return u'%s%s' % (handle, suffix_text)
+            return '{}{}'.format(handle, suffix_text)
         else:
-            return u'!<%s>' % suffix_text
+            return '!<%s>' % suffix_text
 
     def prepare_anchor(self, anchor):
         if not anchor:
             raise EmitterError("anchor must not be empty")
         for ch in anchor:
-            if not (u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'  \
-                    or ch in u'-_'):
+            if not ('0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'  \
+                    or ch in '-_'):
                 raise EmitterError("invalid character %r in the anchor: %r"
                         % (ch.encode('utf-8'), anchor.encode('utf-8')))
         return anchor
@@ -650,7 +649,7 @@ class Emitter(object):
         space_break = False
 
         # Check document indicators.
-        if scalar.startswith(u'---') or scalar.startswith(u'...'):
+        if scalar.startswith('---') or scalar.startswith('...'):
             block_indicators = True
             flow_indicators = True
 
@@ -659,7 +658,7 @@ class Emitter(object):
 
         # Last character or followed by a whitespace.
         followed_by_whitespace = (len(scalar) == 1 or
-                scalar[1] in u'\0 \t\r\n\x85\u2028\u2029')
+                scalar[1] in '\0 \t\r\n\x85\u2028\u2029')
 
         # The previous character is a space.
         previous_space = False
@@ -674,34 +673,34 @@ class Emitter(object):
             # Check for indicators.
             if index == 0:
                 # Leading indicators are special characters.
-                if ch in u'#,[]{}&*!|>\'\"%@`': 
+                if ch in '#,[]{}&*!|>\'\"%@`': 
                     flow_indicators = True
                     block_indicators = True
-                if ch in u'?:':
+                if ch in '?:':
                     flow_indicators = True
                     if followed_by_whitespace:
                         block_indicators = True
-                if ch == u'-' and followed_by_whitespace:
+                if ch == '-' and followed_by_whitespace:
                     flow_indicators = True
                     block_indicators = True
             else:
                 # Some indicators cannot appear within a scalar as well.
-                if ch in u',?[]{}':
+                if ch in ',?[]{}':
                     flow_indicators = True
-                if ch == u':':
+                if ch == ':':
                     flow_indicators = True
                     if followed_by_whitespace:
                         block_indicators = True
-                if ch == u'#' and preceeded_by_whitespace:
+                if ch == '#' and preceeded_by_whitespace:
                     flow_indicators = True
                     block_indicators = True
 
             # Check for line breaks, special, and unicode characters.
-            if ch in u'\n\x85\u2028\u2029':
+            if ch in '\n\x85\u2028\u2029':
                 line_breaks = True
-            if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'):
-                if (ch == u'\x85' or u'\xA0' <= ch <= u'\uD7FF'
-                        or u'\uE000' <= ch <= u'\uFFFD') and ch != u'\uFEFF':
+            if not (ch == '\n' or '\x20' <= ch <= '\x7E'):
+                if (ch == '\x85' or '\xA0' <= ch <= '\uD7FF'
+                        or '\uE000' <= ch <= '\uFFFD') and ch != '\uFEFF':
                     unicode_characters = True
                     if not self.allow_unicode:
                         special_characters = True
@@ -709,7 +708,7 @@ class Emitter(object):
                     special_characters = True
 
             # Detect important whitespace combinations.
-            if ch == u' ':
+            if ch == ' ':
                 if index == 0:
                     leading_space = True
                 if index == len(scalar)-1:
@@ -718,7 +717,7 @@ class Emitter(object):
                     break_space = True
                 previous_space = True
                 previous_break = False
-            elif ch in u'\n\x85\u2028\u2029':
+            elif ch in '\n\x85\u2028\u2029':
                 if index == 0:
                     leading_break = True
                 if index == len(scalar)-1:
@@ -733,9 +732,9 @@ class Emitter(object):
 
             # Prepare for the next character.
             index += 1
-            preceeded_by_whitespace = (ch in u'\0 \t\r\n\x85\u2028\u2029')
+            preceeded_by_whitespace = (ch in '\0 \t\r\n\x85\u2028\u2029')
             followed_by_whitespace = (index+1 >= len(scalar) or
-                    scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029')
+                    scalar[index+1] in '\0 \t\r\n\x85\u2028\u2029')
 
         # Let's decide what styles are allowed.
         allow_flow_plain = True
@@ -794,7 +793,7 @@ class Emitter(object):
     def write_stream_start(self):
         # Write BOM if needed.
         if self.encoding and self.encoding.startswith('utf-16'):
-            self.stream.write(u'\uFEFF'.encode(self.encoding))
+            self.stream.write('\uFEFF'.encode(self.encoding))
 
     def write_stream_end(self):
         self.flush_stream()
@@ -804,7 +803,7 @@ class Emitter(object):
         if self.whitespace or not need_whitespace:
             data = indicator
         else:
-            data = u' '+indicator
+            data = ' '+indicator
         self.whitespace = whitespace
         self.indention = self.indention and indention
         self.column += len(data)
@@ -820,7 +819,7 @@ class Emitter(object):
             self.write_line_break()
         if self.column < indent:
             self.whitespace = True
-            data = u' '*(indent-self.column)
+            data = ' '*(indent-self.column)
             self.column = indent
             if self.encoding:
                 data = data.encode(self.encoding)
@@ -838,14 +837,14 @@ class Emitter(object):
         self.stream.write(data)
 
     def write_version_directive(self, version_text):
-        data = u'%%YAML %s' % version_text
+        data = '%%YAML %s' % version_text
         if self.encoding:
             data = data.encode(self.encoding)
         self.stream.write(data)
         self.write_line_break()
 
     def write_tag_directive(self, handle_text, prefix_text):
-        data = u'%%TAG %s %s' % (handle_text, prefix_text)
+        data = '%TAG {} {}'.format(handle_text, prefix_text)
         if self.encoding:
             data = data.encode(self.encoding)
         self.stream.write(data)
@@ -854,7 +853,7 @@ class Emitter(object):
     # Scalar streams.
 
     def write_single_quoted(self, text, split=True):
-        self.write_indicator(u'\'', True)
+        self.write_indicator('\'', True)
         spaces = False
         breaks = False
         start = end = 0
@@ -863,7 +862,7 @@ class Emitter(object):
             if end < len(text):
                 ch = text[end]
             if spaces:
-                if ch is None or ch != u' ':
+                if ch is None or ch != ' ':
                     if start+1 == end and self.column > self.best_width and split   \
                             and start != 0 and end != len(text):
                         self.write_indent()
@@ -875,18 +874,18 @@ class Emitter(object):
                         self.stream.write(data)
                     start = end
             elif breaks:
-                if ch is None or ch not in u'\n\x85\u2028\u2029':
-                    if text[start] == u'\n':
+                if ch is None or ch not in '\n\x85\u2028\u2029':
+                    if text[start] == '\n':
                         self.write_line_break()
                     for br in text[start:end]:
-                        if br == u'\n':
+                        if br == '\n':
                             self.write_line_break()
                         else:
                             self.write_line_break(br)
                     self.write_indent()
                     start = end
             else:
-                if ch is None or ch in u' \n\x85\u2028\u2029' or ch == u'\'':
+                if ch is None or ch in ' \n\x85\u2028\u2029' or ch == '\'':
                     if start < end:
                         data = text[start:end]
                         self.column += len(data)
@@ -894,49 +893,49 @@ class Emitter(object):
                             data = data.encode(self.encoding)
                         self.stream.write(data)
                         start = end
-            if ch == u'\'':
-                data = u'\'\''
+            if ch == '\'':
+                data = '\'\''
                 self.column += 2
                 if self.encoding:
                     data = data.encode(self.encoding)
                 self.stream.write(data)
                 start = end + 1
             if ch is not None:
-                spaces = (ch == u' ')
-                breaks = (ch in u'\n\x85\u2028\u2029')
+                spaces = (ch == ' ')
+                breaks = (ch in '\n\x85\u2028\u2029')
             end += 1
-        self.write_indicator(u'\'', False)
+        self.write_indicator('\'', False)
 
     ESCAPE_REPLACEMENTS = {
-        u'\0':      u'0',
-        u'\x07':    u'a',
-        u'\x08':    u'b',
-        u'\x09':    u't',
-        u'\x0A':    u'n',
-        u'\x0B':    u'v',
-        u'\x0C':    u'f',
-        u'\x0D':    u'r',
-        u'\x1B':    u'e',
-        u'\"':      u'\"',
-        u'\\':      u'\\',
-        u'\x85':    u'N',
-        u'\xA0':    u'_',
-        u'\u2028':  u'L',
-        u'\u2029':  u'P',
+        '\0':      '0',
+        '\x07':    'a',
+        '\x08':    'b',
+        '\x09':    't',
+        '\x0A':    'n',
+        '\x0B':    'v',
+        '\x0C':    'f',
+        '\x0D':    'r',
+        '\x1B':    'e',
+        '\"':      '\"',
+        '\\':      '\\',
+        '\x85':    'N',
+        '\xA0':    '_',
+        '\u2028':  'L',
+        '\u2029':  'P',
     }
 
     def write_double_quoted(self, text, split=True):
-        self.write_indicator(u'"', True)
+        self.write_indicator('"', True)
         start = end = 0
         while end <= len(text):
             ch = None
             if end < len(text):
                 ch = text[end]
-            if ch is None or ch in u'"\\\x85\u2028\u2029\uFEFF' \
-                    or not (u'\x20' <= ch <= u'\x7E'
+            if ch is None or ch in '"\\\x85\u2028\u2029\uFEFF' \
+                    or not ('\x20' <= ch <= '\x7E'
                         or (self.allow_unicode
-                            and (u'\xA0' <= ch <= u'\uD7FF'
-                                or u'\uE000' <= ch <= u'\uFFFD'))):
+                            and ('\xA0' <= ch <= '\uD7FF'
+                                or '\uE000' <= ch <= '\uFFFD'))):
                 if start < end:
                     data = text[start:end]
                     self.column += len(data)
@@ -946,21 +945,21 @@ class Emitter(object):
                     start = end
                 if ch is not None:
                     if ch in self.ESCAPE_REPLACEMENTS:
-                        data = u'\\'+self.ESCAPE_REPLACEMENTS[ch]
-                    elif ch <= u'\xFF':
-                        data = u'\\x%02X' % ord(ch)
-                    elif ch <= u'\uFFFF':
-                        data = u'\\u%04X' % ord(ch)
+                        data = '\\'+self.ESCAPE_REPLACEMENTS[ch]
+                    elif ch <= '\xFF':
+                        data = '\\x%02X' % ord(ch)
+                    elif ch <= '\uFFFF':
+                        data = '\\u%04X' % ord(ch)
                     else:
-                        data = u'\\U%08X' % ord(ch)
+                        data = '\\U%08X' % ord(ch)
                     self.column += len(data)
                     if self.encoding:
                         data = data.encode(self.encoding)
                     self.stream.write(data)
                     start = end+1
-            if 0 < end < len(text)-1 and (ch == u' ' or start >= end)   \
+            if 0 < end < len(text)-1 and (ch == ' ' or start >= end)   \
                     and self.column+(end-start) > self.best_width and split:
-                data = text[start:end]+u'\\'
+                data = text[start:end]+'\\'
                 if start < end:
                     start = end
                 self.column += len(data)
@@ -970,30 +969,30 @@ class Emitter(object):
                 self.write_indent()
                 self.whitespace = False
                 self.indention = False
-                if text[start] == u' ':
-                    data = u'\\'
+                if text[start] == ' ':
+                    data = '\\'
                     self.column += len(data)
                     if self.encoding:
                         data = data.encode(self.encoding)
                     self.stream.write(data)
             end += 1
-        self.write_indicator(u'"', False)
+        self.write_indicator('"', False)
 
     def determine_block_hints(self, text):
-        hints = u''
+        hints = ''
         if text:
-            if text[0] in u' \n\x85\u2028\u2029':
-                hints += unicode(self.best_indent)
-            if text[-1] not in u'\n\x85\u2028\u2029':
-                hints += u'-'
-            elif len(text) == 1 or text[-2] in u'\n\x85\u2028\u2029':
-                hints += u'+'
+            if text[0] in ' \n\x85\u2028\u2029':
+                hints += str(self.best_indent)
+            if text[-1] not in '\n\x85\u2028\u2029':
+                hints += '-'
+            elif len(text) == 1 or text[-2] in '\n\x85\u2028\u2029':
+                hints += '+'
         return hints
 
     def write_folded(self, text):
         hints = self.determine_block_hints(text)
-        self.write_indicator(u'>'+hints, True)
-        if hints[-1:] == u'+':
+        self.write_indicator('>'+hints, True)
+        if hints[-1:] == '+':
             self.open_ended = True
         self.write_line_break()
         leading_space = True
@@ -1005,13 +1004,13 @@ class Emitter(object):
             if end < len(text):
                 ch = text[end]
             if breaks:
-                if ch is None or ch not in u'\n\x85\u2028\u2029':
-                    if not leading_space and ch is not None and ch != u' '  \
-                            and text[start] == u'\n':
+                if ch is None or ch not in '\n\x85\u2028\u2029':
+                    if not leading_space and ch is not None and ch != ' '  \
+                            and text[start] == '\n':
                         self.write_line_break()
-                    leading_space = (ch == u' ')
+                    leading_space = (ch == ' ')
                     for br in text[start:end]:
-                        if br == u'\n':
+                        if br == '\n':
                             self.write_line_break()
                         else:
                             self.write_line_break(br)
@@ -1019,7 +1018,7 @@ class Emitter(object):
                         self.write_indent()
                     start = end
             elif spaces:
-                if ch != u' ':
+                if ch != ' ':
                     if start+1 == end and self.column > self.best_width:
                         self.write_indent()
                     else:
@@ -1030,7 +1029,7 @@ class Emitter(object):
                         self.stream.write(data)
                     start = end
             else:
-                if ch is None or ch in u' \n\x85\u2028\u2029':
+                if ch is None or ch in ' \n\x85\u2028\u2029':
                     data = text[start:end]
                     self.column += len(data)
                     if self.encoding:
@@ -1040,14 +1039,14 @@ class Emitter(object):
                         self.write_line_break()
                     start = end
             if ch is not None:
-                breaks = (ch in u'\n\x85\u2028\u2029')
-                spaces = (ch == u' ')
+                breaks = (ch in '\n\x85\u2028\u2029')
+                spaces = (ch == ' ')
             end += 1
 
     def write_literal(self, text):
         hints = self.determine_block_hints(text)
-        self.write_indicator(u'|'+hints, True)
-        if hints[-1:] == u'+':
+        self.write_indicator('|'+hints, True)
+        if hints[-1:] == '+':
             self.open_ended = True
         self.write_line_break()
         breaks = True
@@ -1057,9 +1056,9 @@ class Emitter(object):
             if end < len(text):
                 ch = text[end]
             if breaks:
-                if ch is None or ch not in u'\n\x85\u2028\u2029':
+                if ch is None or ch not in '\n\x85\u2028\u2029':
                     for br in text[start:end]:
-                        if br == u'\n':
+                        if br == '\n':
                             self.write_line_break()
                         else:
                             self.write_line_break(br)
@@ -1067,7 +1066,7 @@ class Emitter(object):
                         self.write_indent()
                     start = end
             else:
-                if ch is None or ch in u'\n\x85\u2028\u2029':
+                if ch is None or ch in '\n\x85\u2028\u2029':
                     data = text[start:end]
                     if self.encoding:
                         data = data.encode(self.encoding)
@@ -1076,7 +1075,7 @@ class Emitter(object):
                         self.write_line_break()
                     start = end
             if ch is not None:
-                breaks = (ch in u'\n\x85\u2028\u2029')
+                breaks = (ch in '\n\x85\u2028\u2029')
             end += 1
 
     def write_plain(self, text, split=True):
@@ -1085,7 +1084,7 @@ class Emitter(object):
         if not text:
             return
         if not self.whitespace:
-            data = u' '
+            data = ' '
             self.column += len(data)
             if self.encoding:
                 data = data.encode(self.encoding)
@@ -1100,7 +1099,7 @@ class Emitter(object):
             if end < len(text):
                 ch = text[end]
             if spaces:
-                if ch != u' ':
+                if ch != ' ':
                     if start+1 == end and self.column > self.best_width and split:
                         self.write_indent()
                         self.whitespace = False
@@ -1113,11 +1112,11 @@ class Emitter(object):
                         self.stream.write(data)
                     start = end
             elif breaks:
-                if ch not in u'\n\x85\u2028\u2029':
-                    if text[start] == u'\n':
+                if ch not in '\n\x85\u2028\u2029':
+                    if text[start] == '\n':
                         self.write_line_break()
                     for br in text[start:end]:
-                        if br == u'\n':
+                        if br == '\n':
                             self.write_line_break()
                         else:
                             self.write_line_break(br)
@@ -1126,7 +1125,7 @@ class Emitter(object):
                     self.indention = False
                     start = end
             else:
-                if ch is None or ch in u' \n\x85\u2028\u2029':
+                if ch is None or ch in ' \n\x85\u2028\u2029':
                     data = text[start:end]
                     self.column += len(data)
                     if self.encoding:
@@ -1134,7 +1133,7 @@ class Emitter(object):
                     self.stream.write(data)
                     start = end
             if ch is not None:
-                spaces = (ch == u' ')
-                breaks = (ch in u'\n\x85\u2028\u2029')
+                spaces = (ch == ' ')
+                breaks = (ch in '\n\x85\u2028\u2029')
             end += 1
 
diff --git a/python/pyyaml/lib/yaml/error.py b/python/pyyaml/lib/yaml/error.py
index 577686db5f..6f7011a2c4 100644
--- a/python/pyyaml/lib/yaml/error.py
+++ b/python/pyyaml/lib/yaml/error.py
@@ -1,7 +1,6 @@
-
 __all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
 
-class Mark(object):
+class Mark:
 
     def __init__(self, name, index, line, column, buffer, pointer):
         self.name = name
@@ -16,7 +15,7 @@ class Mark(object):
             return None
         head = ''
         start = self.pointer
-        while start > 0 and self.buffer[start-1] not in u'\0\r\n\x85\u2028\u2029':
+        while start > 0 and self.buffer[start-1] not in '\0\r\n\x85\u2028\u2029':
             start -= 1
             if self.pointer-start > max_length/2-1:
                 head = ' ... '
@@ -24,7 +23,7 @@ class Mark(object):
                 break
         tail = ''
         end = self.pointer
-        while end < len(self.buffer) and self.buffer[end] not in u'\0\r\n\x85\u2028\u2029':
+        while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029':
             end += 1
             if end-self.pointer > max_length/2-1:
                 tail = ' ... '
diff --git a/python/pyyaml/lib/yaml/events.py b/python/pyyaml/lib/yaml/events.py
index f79ad389cb..e54499400a 100644
--- a/python/pyyaml/lib/yaml/events.py
+++ b/python/pyyaml/lib/yaml/events.py
@@ -1,16 +1,15 @@
-
 # Abstract classes.
 
-class Event(object):
+class Event:
     def __init__(self, start_mark=None, end_mark=None):
         self.start_mark = start_mark
         self.end_mark = end_mark
     def __repr__(self):
         attributes = [key for key in ['anchor', 'tag', 'implicit', 'value']
                 if hasattr(self, key)]
-        arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
+        arguments = ', '.join(['{}={!r}'.format(key, getattr(self, key))
                 for key in attributes])
-        return '%s(%s)' % (self.__class__.__name__, arguments)
+        return '{}({})'.format(self.__class__.__name__, arguments)
 
 class NodeEvent(Event):
     def __init__(self, anchor, start_mark=None, end_mark=None):
diff --git a/python/pyyaml/lib/yaml/loader.py b/python/pyyaml/lib/yaml/loader.py
index 293ff467b1..559275b02a 100644
--- a/python/pyyaml/lib/yaml/loader.py
+++ b/python/pyyaml/lib/yaml/loader.py
@@ -1,12 +1,11 @@
-
 __all__ = ['BaseLoader', 'SafeLoader', 'Loader']
 
-from reader import *
-from scanner import *
-from parser import *
-from composer import *
-from constructor import *
-from resolver import *
+from .reader import *
+from .scanner import *
+from .parser import *
+from .composer import *
+from .constructor import *
+from .resolver import *
 
 class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver):
 
diff --git a/python/pyyaml/lib/yaml/nodes.py b/python/pyyaml/lib/yaml/nodes.py
index c4f070c41e..c9a20df12a 100644
--- a/python/pyyaml/lib/yaml/nodes.py
+++ b/python/pyyaml/lib/yaml/nodes.py
@@ -1,5 +1,4 @@
-
-class Node(object):
+class Node:
     def __init__(self, tag, value, start_mark, end_mark):
         self.tag = tag
         self.value = value
@@ -20,7 +19,7 @@ class Node(object):
         #    else:
         #        value = repr(value)
         value = repr(value)
-        return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
+        return '{}(tag={!r}, value={})'.format(self.__class__.__name__, self.tag, value)
 
 class ScalarNode(Node):
     id = 'scalar'
diff --git a/python/pyyaml/lib/yaml/parser.py b/python/pyyaml/lib/yaml/parser.py
index f9e3057f33..2174c21f5c 100644
--- a/python/pyyaml/lib/yaml/parser.py
+++ b/python/pyyaml/lib/yaml/parser.py
@@ -1,4 +1,3 @@
-
 # The following YAML grammar is LL(1) and is parsed by a recursive descent
 # parser.
 #
@@ -61,21 +60,21 @@
 
 __all__ = ['Parser', 'ParserError']
 
-from error import MarkedYAMLError
-from tokens import *
-from events import *
-from scanner import *
+from .error import MarkedYAMLError
+from .tokens import *
+from .events import *
+from .scanner import *
 
 class ParserError(MarkedYAMLError):
     pass
 
-class Parser(object):
+class Parser:
     # Since writing a recursive-descendant parser is a straightforward task, we
     # do not give many comments here.
 
     DEFAULT_TAGS = {
-        u'!':   u'!',
-        u'!!':  u'tag:yaml.org,2002:',
+        '!':   '!',
+        '!!':  'tag:yaml.org,2002:',
     }
 
     def __init__(self):
@@ -219,7 +218,7 @@ class Parser(object):
         self.tag_handles = {}
         while self.check_token(DirectiveToken):
             token = self.get_token()
-            if token.name == u'YAML':
+            if token.name == 'YAML':
                 if self.yaml_version is not None:
                     raise ParserError(None, None,
                             "found duplicate YAML directive", token.start_mark)
@@ -229,7 +228,7 @@ class Parser(object):
                             "found incompatible YAML document (version 1.* is required)",
                             token.start_mark)
                 self.yaml_version = token.value
-            elif token.name == u'TAG':
+            elif token.name == 'TAG':
                 handle, prefix = token.value
                 if handle in self.tag_handles:
                     raise ParserError(None, None,
@@ -315,7 +314,7 @@ class Parser(object):
             if start_mark is None:
                 start_mark = end_mark = self.peek_token().start_mark
             event = None
-            implicit = (tag is None or tag == u'!')
+            implicit = (tag is None or tag == '!')
             if indentless_sequence and self.check_token(BlockEntryToken):
                 end_mark = self.peek_token().end_mark
                 event = SequenceStartEvent(anchor, tag, implicit,
@@ -325,7 +324,7 @@ class Parser(object):
                 if self.check_token(ScalarToken):
                     token = self.get_token()
                     end_mark = token.end_mark
-                    if (token.plain and tag is None) or tag == u'!':
+                    if (token.plain and tag is None) or tag == '!':
                         implicit = (True, False)
                     elif tag is None:
                         implicit = (False, True)
@@ -357,7 +356,7 @@ class Parser(object):
                 elif anchor is not None or tag is not None:
                     # Empty scalars are allowed even if a tag or an anchor is
                     # specified.
-                    event = ScalarEvent(anchor, tag, (implicit, False), u'',
+                    event = ScalarEvent(anchor, tag, (implicit, False), '',
                             start_mark, end_mark)
                     self.state = self.states.pop()
                 else:
@@ -585,5 +584,5 @@ class Parser(object):
         return self.process_empty_scalar(self.peek_token().start_mark)
 
     def process_empty_scalar(self, mark):
-        return ScalarEvent(None, None, (True, False), u'', mark, mark)
+        return ScalarEvent(None, None, (True, False), '', mark, mark)
 
diff --git a/python/pyyaml/lib/yaml/reader.py b/python/pyyaml/lib/yaml/reader.py
index 3249e6b9f5..c6d98ff1a7 100644
--- a/python/pyyaml/lib/yaml/reader.py
+++ b/python/pyyaml/lib/yaml/reader.py
@@ -17,7 +17,7 @@
 
 __all__ = ['Reader', 'ReaderError']
 
-from error import YAMLError, Mark
+from .error import YAMLError, Mark
 
 import codecs, re
 
@@ -61,7 +61,7 @@ class Reader(object):
         self.stream = None
         self.stream_pointer = 0
         self.eof = True
-        self.buffer = u''
+        self.buffer = ''
         self.pointer = 0
         self.raw_buffer = None
         self.raw_decode = None
@@ -69,10 +69,10 @@ class Reader(object):
         self.index = 0
         self.line = 0
         self.column = 0
-        if isinstance(stream, unicode):
+        if isinstance(stream, str):
             self.name = "<unicode string>"
             self.check_printable(stream)
-            self.buffer = stream+u'\0'
+            self.buffer = stream+'\0'
         elif isinstance(stream, str):
             self.name = "<string>"
             self.raw_buffer = stream
@@ -103,11 +103,11 @@ class Reader(object):
             ch = self.buffer[self.pointer]
             self.pointer += 1
             self.index += 1
-            if ch in u'\n\x85\u2028\u2029'  \
-                    or (ch == u'\r' and self.buffer[self.pointer] != u'\n'):
+            if ch in '\n\x85\u2028\u2029'  \
+                    or (ch == '\r' and self.buffer[self.pointer] != '\n'):
                 self.line += 1
                 self.column = 0
-            elif ch != u'\uFEFF':
+            elif ch != '\uFEFF':
                 self.column += 1
             length -= 1
 
@@ -122,7 +122,7 @@ class Reader(object):
     def determine_encoding(self):
         while not self.eof and len(self.raw_buffer) < 2:
             self.update_raw()
-        if not isinstance(self.raw_buffer, unicode):
+        if not isinstance(self.raw_buffer, str):
             if self.raw_buffer.startswith(codecs.BOM_UTF16_LE):
                 self.raw_decode = codecs.utf_16_le_decode
                 self.encoding = 'utf-16-le'
@@ -134,7 +134,7 @@ class Reader(object):
                 self.encoding = 'utf-8'
         self.update(1)
 
-    NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
+    NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
     def check_printable(self, data):
         match = self.NON_PRINTABLE.search(data)
         if match:
@@ -155,7 +155,7 @@ class Reader(object):
                 try:
                     data, converted = self.raw_decode(self.raw_buffer,
                             'strict', self.eof)
-                except UnicodeDecodeError, exc:
+                except UnicodeDecodeError as exc:
                     character = exc.object[exc.start]
                     if self.stream is not None:
                         position = self.stream_pointer-len(self.raw_buffer)+exc.start
@@ -170,7 +170,7 @@ class Reader(object):
             self.buffer += data
             self.raw_buffer = self.raw_buffer[converted:]
             if self.eof:
-                self.buffer += u'\0'
+                self.buffer += '\0'
                 self.raw_buffer = None
                 break
 
diff --git a/python/pyyaml/lib/yaml/representer.py b/python/pyyaml/lib/yaml/representer.py
index 5f4fc70dbc..41c08ff892 100644
--- a/python/pyyaml/lib/yaml/representer.py
+++ b/python/pyyaml/lib/yaml/representer.py
@@ -1,18 +1,18 @@
-
+import six
 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
     'RepresenterError']
 
-from error import *
-from nodes import *
+from .error import *
+from .nodes import *
 
 import datetime
 
-import sys, copy_reg, types
+import sys, six.moves.copyreg, types
 
 class RepresenterError(YAMLError):
     pass
 
-class BaseRepresenter(object):
+class BaseRepresenter:
 
     yaml_representers = {}
     yaml_multi_representers = {}
@@ -66,7 +66,7 @@ class BaseRepresenter(object):
                 elif None in self.yaml_representers:
                     node = self.yaml_representers[None](self, data)
                 else:
-                    node = ScalarNode(None, unicode(data))
+                    node = ScalarNode(None, str(data))
         #if alias_key is not None:
         #    self.represented_objects[alias_key] = node
         return node
@@ -116,7 +116,7 @@ class BaseRepresenter(object):
             self.represented_objects[self.alias_key] = node
         best_style = True
         if hasattr(mapping, 'items'):
-            mapping = mapping.items()
+            mapping = list(mapping.items())
             mapping.sort()
         for item_key, item_value in mapping:
             node_key = self.represent_data(item_key)
@@ -141,44 +141,44 @@ class SafeRepresenter(BaseRepresenter):
     def ignore_aliases(self, data):
         if data in [None, ()]:
             return True
-        if isinstance(data, (str, unicode, bool, int, float)):
+        if isinstance(data, (str, str, bool, int, float)):
             return True
 
     def represent_none(self, data):
-        return self.represent_scalar(u'tag:yaml.org,2002:null',
-                u'null')
+        return self.represent_scalar('tag:yaml.org,2002:null',
+                'null')
 
     def represent_str(self, data):
         tag = None
         style = None
         try:
-            data = unicode(data, 'ascii')
-            tag = u'tag:yaml.org,2002:str'
+            data = str(data, 'ascii')
+            tag = 'tag:yaml.org,2002:str'
         except UnicodeDecodeError:
             try:
-                data = unicode(data, 'utf-8')
-                tag = u'tag:yaml.org,2002:str'
+                data = str(data, 'utf-8')
+                tag = 'tag:yaml.org,2002:str'
             except UnicodeDecodeError:
                 data = data.encode('base64')
-                tag = u'tag:yaml.org,2002:binary'
+                tag = 'tag:yaml.org,2002:binary'
                 style = '|'
         return self.represent_scalar(tag, data, style=style)
 
     def represent_unicode(self, data):
-        return self.represent_scalar(u'tag:yaml.org,2002:str', data)
+        return self.represent_scalar('tag:yaml.org,2002:str', data)
 
     def represent_bool(self, data):
         if data:
-            value = u'true'
+            value = 'true'
         else:
-            value = u'false'
-        return self.represent_scalar(u'tag:yaml.org,2002:bool', value)
+            value = 'false'
+        return self.represent_scalar('tag:yaml.org,2002:bool', value)
 
     def represent_int(self, data):
-        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
+        return self.represent_scalar('tag:yaml.org,2002:int', str(data))
 
     def represent_long(self, data):
-        return self.represent_scalar(u'tag:yaml.org,2002:int', unicode(data))
+        return self.represent_scalar('tag:yaml.org,2002:int', str(data))
 
     inf_value = 1e300
     while repr(inf_value) != repr(inf_value*inf_value):
@@ -186,13 +186,13 @@ class SafeRepresenter(BaseRepresenter):
 
     def represent_float(self, data):
         if data != data or (data == 0.0 and data == 1.0):
-            value = u'.nan'
+            value = '.nan'
         elif data == self.inf_value:
-            value = u'.inf'
+            value = '.inf'
         elif data == -self.inf_value:
-            value = u'-.inf'
+            value = '-.inf'
         else:
-            value = unicode(repr(data)).lower()
+            value = str(repr(data)).lower()
             # Note that in some cases `repr(data)` represents a float number
             # without the decimal parts.  For instance:
             #   >>> repr(1e17)
@@ -200,9 +200,9 @@ class SafeRepresenter(BaseRepresenter):
             # Unfortunately, this is not a valid float representation according
             # to the definition of the `!!float` tag.  We fix this by adding
             # '.0' before the 'e' symbol.
-            if u'.' not in value and u'e' in value:
-                value = value.replace(u'e', u'.0e', 1)
-        return self.represent_scalar(u'tag:yaml.org,2002:float', value)
+            if '.' not in value and 'e' in value:
+                value = value.replace('e', '.0e', 1)
+        return self.represent_scalar('tag:yaml.org,2002:float', value)
 
     def represent_list(self, data):
         #pairs = (len(data) > 0 and isinstance(data, list))
@@ -212,7 +212,7 @@ class SafeRepresenter(BaseRepresenter):
         #            pairs = False
         #            break
         #if not pairs:
-            return self.represent_sequence(u'tag:yaml.org,2002:seq', data)
+            return self.represent_sequence('tag:yaml.org,2002:seq', data)
         #value = []
         #for item_key, item_value in data:
         #    value.append(self.represent_mapping(u'tag:yaml.org,2002:map',
@@ -220,21 +220,21 @@ class SafeRepresenter(BaseRepresenter):
         #return SequenceNode(u'tag:yaml.org,2002:pairs', value)
 
     def represent_dict(self, data):
-        return self.represent_mapping(u'tag:yaml.org,2002:map', data)
+        return self.represent_mapping('tag:yaml.org,2002:map', data)
 
     def represent_set(self, data):
         value = {}
         for key in data:
             value[key] = None
-        return self.represent_mapping(u'tag:yaml.org,2002:set', value)
+        return self.represent_mapping('tag:yaml.org,2002:set', value)
 
     def represent_date(self, data):
-        value = unicode(data.isoformat())
-        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
+        value = str(data.isoformat())
+        return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
 
     def represent_datetime(self, data):
-        value = unicode(data.isoformat(' '))
-        return self.represent_scalar(u'tag:yaml.org,2002:timestamp', value)
+        value = str(data.isoformat(' '))
+        return self.represent_scalar('tag:yaml.org,2002:timestamp', value)
 
     def represent_yaml_object(self, tag, data, cls, flow_style=None):
         if hasattr(data, '__getstate__'):
@@ -252,7 +252,7 @@ SafeRepresenter.add_representer(type(None),
 SafeRepresenter.add_representer(str,
         SafeRepresenter.represent_str)
 
-SafeRepresenter.add_representer(unicode,
+SafeRepresenter.add_representer(str,
         SafeRepresenter.represent_unicode)
 
 SafeRepresenter.add_representer(bool,
@@ -261,7 +261,7 @@ SafeRepresenter.add_representer(bool,
 SafeRepresenter.add_representer(int,
         SafeRepresenter.represent_int)
 
-SafeRepresenter.add_representer(long,
+SafeRepresenter.add_representer(int,
         SafeRepresenter.represent_long)
 
 SafeRepresenter.add_representer(float,
@@ -294,15 +294,15 @@ class Representer(SafeRepresenter):
         tag = None
         style = None
         try:
-            data = unicode(data, 'ascii')
-            tag = u'tag:yaml.org,2002:str'
+            data = str(data, 'ascii')
+            tag = 'tag:yaml.org,2002:str'
         except UnicodeDecodeError:
             try:
-                data = unicode(data, 'utf-8')
-                tag = u'tag:yaml.org,2002:python/str'
+                data = str(data, 'utf-8')
+                tag = 'tag:yaml.org,2002:python/str'
             except UnicodeDecodeError:
                 data = data.encode('base64')
-                tag = u'tag:yaml.org,2002:binary'
+                tag = 'tag:yaml.org,2002:binary'
                 style = '|'
         return self.represent_scalar(tag, data, style=style)
 
@@ -310,38 +310,38 @@ class Representer(SafeRepresenter):
         tag = None
         try:
             data.encode('ascii')
-            tag = u'tag:yaml.org,2002:python/unicode'
+            tag = 'tag:yaml.org,2002:python/unicode'
         except UnicodeEncodeError:
-            tag = u'tag:yaml.org,2002:str'
+            tag = 'tag:yaml.org,2002:str'
         return self.represent_scalar(tag, data)
 
     def represent_long(self, data):
-        tag = u'tag:yaml.org,2002:int'
+        tag = 'tag:yaml.org,2002:int'
         if int(data) is not data:
-            tag = u'tag:yaml.org,2002:python/long'
-        return self.represent_scalar(tag, unicode(data))
+            tag = 'tag:yaml.org,2002:python/long'
+        return self.represent_scalar(tag, str(data))
 
     def represent_complex(self, data):
         if data.imag == 0.0:
-            data = u'%r' % data.real
+            data = '%r' % data.real
         elif data.real == 0.0:
-            data = u'%rj' % data.imag
+            data = '%rj' % data.imag
         elif data.imag > 0:
-            data = u'%r+%rj' % (data.real, data.imag)
+            data = '{!r}+{!r}j'.format(data.real, data.imag)
         else:
-            data = u'%r%rj' % (data.real, data.imag)
-        return self.represent_scalar(u'tag:yaml.org,2002:python/complex', data)
+            data = '{!r}{!r}j'.format(data.real, data.imag)
+        return self.represent_scalar('tag:yaml.org,2002:python/complex', data)
 
     def represent_tuple(self, data):
-        return self.represent_sequence(u'tag:yaml.org,2002:python/tuple', data)
+        return self.represent_sequence('tag:yaml.org,2002:python/tuple', data)
 
     def represent_name(self, data):
-        name = u'%s.%s' % (data.__module__, data.__name__)
-        return self.represent_scalar(u'tag:yaml.org,2002:python/name:'+name, u'')
+        name = '{}.{}'.format(data.__module__, data.__name__)
+        return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '')
 
     def represent_module(self, data):
         return self.represent_scalar(
-                u'tag:yaml.org,2002:python/module:'+data.__name__, u'')
+                'tag:yaml.org,2002:python/module:'+data.__name__, '')
 
     def represent_instance(self, data):
         # For instances of classic classes, we use __getinitargs__ and
@@ -362,7 +362,7 @@ class Representer(SafeRepresenter):
         # !!python/object/new node.
 
         cls = data.__class__
-        class_name = u'%s.%s' % (cls.__module__, cls.__name__)
+        class_name = '{}.{}'.format(cls.__module__, cls.__name__)
         args = None
         state = None
         if hasattr(data, '__getinitargs__'):
@@ -373,16 +373,16 @@ class Representer(SafeRepresenter):
             state = data.__dict__
         if args is None and isinstance(state, dict):
             return self.represent_mapping(
-                    u'tag:yaml.org,2002:python/object:'+class_name, state)
+                    'tag:yaml.org,2002:python/object:'+class_name, state)
         if isinstance(state, dict) and not state:
             return self.represent_sequence(
-                    u'tag:yaml.org,2002:python/object/new:'+class_name, args)
+                    'tag:yaml.org,2002:python/object/new:'+class_name, args)
         value = {}
         if args:
             value['args'] = args
         value['state'] = state
         return self.represent_mapping(
-                u'tag:yaml.org,2002:python/object/new:'+class_name, value)
+                'tag:yaml.org,2002:python/object/new:'+class_name, value)
 
     def represent_object(self, data):
         # We use __reduce__ API to save the data. data.__reduce__ returns
@@ -402,8 +402,8 @@ class Representer(SafeRepresenter):
         # !!python/object/apply node.
 
         cls = type(data)
-        if cls in copy_reg.dispatch_table:
-            reduce = copy_reg.dispatch_table[cls](data)
+        if cls in six.moves.copyreg.dispatch_table:
+            reduce = six.moves.copyreg.dispatch_table[cls](data)
         elif hasattr(data, '__reduce_ex__'):
             reduce = data.__reduce_ex__(2)
         elif hasattr(data, '__reduce__'):
@@ -422,16 +422,16 @@ class Representer(SafeRepresenter):
         if function.__name__ == '__newobj__':
             function = args[0]
             args = args[1:]
-            tag = u'tag:yaml.org,2002:python/object/new:'
+            tag = 'tag:yaml.org,2002:python/object/new:'
             newobj = True
         else:
-            tag = u'tag:yaml.org,2002:python/object/apply:'
+            tag = 'tag:yaml.org,2002:python/object/apply:'
             newobj = False
-        function_name = u'%s.%s' % (function.__module__, function.__name__)
+        function_name = '{}.{}'.format(function.__module__, function.__name__)
         if not args and not listitems and not dictitems \
                 and isinstance(state, dict) and newobj:
             return self.represent_mapping(
-                    u'tag:yaml.org,2002:python/object:'+function_name, state)
+                    'tag:yaml.org,2002:python/object:'+function_name, state)
         if not listitems and not dictitems  \
                 and isinstance(state, dict) and not state:
             return self.represent_sequence(tag+function_name, args)
@@ -449,10 +449,10 @@ class Representer(SafeRepresenter):
 Representer.add_representer(str,
         Representer.represent_str)
 
-Representer.add_representer(unicode,
+Representer.add_representer(str,
         Representer.represent_unicode)
 
-Representer.add_representer(long,
+Representer.add_representer(int,
         Representer.represent_long)
 
 Representer.add_representer(complex,
@@ -464,7 +464,7 @@ Representer.add_representer(tuple,
 Representer.add_representer(type,
         Representer.represent_name)
 
-Representer.add_representer(types.ClassType,
+Representer.add_representer(type,
         Representer.represent_name)
 
 Representer.add_representer(types.FunctionType,
diff --git a/python/pyyaml/lib/yaml/resolver.py b/python/pyyaml/lib/yaml/resolver.py
index 6b5ab87596..72b33986b4 100644
--- a/python/pyyaml/lib/yaml/resolver.py
+++ b/python/pyyaml/lib/yaml/resolver.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseResolver', 'Resolver']
 
 from error import *
@@ -11,9 +10,9 @@ class ResolverError(YAMLError):
 
 class BaseResolver(object):
 
-    DEFAULT_SCALAR_TAG = u'tag:yaml.org,2002:str'
-    DEFAULT_SEQUENCE_TAG = u'tag:yaml.org,2002:seq'
-    DEFAULT_MAPPING_TAG = u'tag:yaml.org,2002:map'
+    DEFAULT_SCALAR_TAG = 'tag:yaml.org,2002:str'
+    DEFAULT_SEQUENCE_TAG = 'tag:yaml.org,2002:seq'
+    DEFAULT_MAPPING_TAG = 'tag:yaml.org,2002:map'
 
     yaml_implicit_resolvers = {}
     yaml_path_resolvers = {}
@@ -139,8 +138,8 @@ class BaseResolver(object):
 
     def resolve(self, kind, value, implicit):
         if kind is ScalarNode and implicit[0]:
-            if value == u'':
-                resolvers = self.yaml_implicit_resolvers.get(u'', [])
+            if value == '':
+                resolvers = self.yaml_implicit_resolvers.get('', [])
             else:
                 resolvers = self.yaml_implicit_resolvers.get(value[0], [])
             resolvers += self.yaml_implicit_resolvers.get(None, [])
@@ -165,60 +164,60 @@ class Resolver(BaseResolver):
     pass
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:bool',
-        re.compile(ur'''^(?:yes|Yes|YES|no|No|NO
+        'tag:yaml.org,2002:bool',
+        re.compile(r'''^(?:yes|Yes|YES|no|No|NO
                     |true|True|TRUE|false|False|FALSE
                     |on|On|ON|off|Off|OFF)$''', re.X),
-        list(u'yYnNtTfFoO'))
+        list('yYnNtTfFoO'))
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:float',
-        re.compile(ur'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
+        'tag:yaml.org,2002:float',
+        re.compile(urr'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
                     |\.[0-9_]+(?:[eE][-+][0-9]+)?
                     |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
                     |[-+]?\.(?:inf|Inf|INF)
                     |\.(?:nan|NaN|NAN))$''', re.X),
-        list(u'-+0123456789.'))
+        list('-+0123456789.'))
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:int',
-        re.compile(ur'''^(?:[-+]?0b[0-1_]+
+        'tag:yaml.org,2002:int',
+        re.compile(r'''^(?:[-+]?0b[0-1_]+
                     |[-+]?0[0-7_]+
                     |[-+]?(?:0|[1-9][0-9_]*)
                     |[-+]?0x[0-9a-fA-F_]+
                     |[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)$''', re.X),
-        list(u'-+0123456789'))
+        list('-+0123456789'))
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:merge',
-        re.compile(ur'^(?:<<)$'),
-        [u'<'])
+        'tag:yaml.org,2002:merge',
+        re.compile(r'^(?:<<)$'),
+        ['<'])
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:null',
-        re.compile(ur'''^(?: ~
+        'tag:yaml.org,2002:null',
+        re.compile(r'''^(?: ~
                     |null|Null|NULL
                     | )$''', re.X),
-        [u'~', u'n', u'N', u''])
+        ['~', 'n', 'N', ''])
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:timestamp',
-        re.compile(ur'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
+        'tag:yaml.org,2002:timestamp',
+        re.compile(r'''^(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
                     |[0-9][0-9][0-9][0-9] -[0-9][0-9]? -[0-9][0-9]?
                      (?:[Tt]|[ \t]+)[0-9][0-9]?
-                     :[0-9][0-9] :[0-9][0-9] (?:\.[0-9]*)?
+                     :[0-9][0-9] :[0-9][0-9] (?:\\.[0-9]*)?
                      (?:[ \t]*(?:Z|[-+][0-9][0-9]?(?::[0-9][0-9])?))?)$''', re.X),
-        list(u'0123456789'))
+        list('0123456789'))
 
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:value',
-        re.compile(ur'^(?:=)$'),
-        [u'='])
+        'tag:yaml.org,2002:value',
+        re.compile(r'^(?:=)$'),
+        ['='])
 
 # The following resolver is only for documentation purposes. It cannot work
 # because plain scalars cannot start with '!', '&', or '*'.
 Resolver.add_implicit_resolver(
-        u'tag:yaml.org,2002:yaml',
-        re.compile(ur'^(?:!|&|\*)$'),
-        list(u'!&*'))
+        'tag:yaml.org,2002:yaml',
+        re.compile(urr'^(?:!|&|\*)$'),
+        list('!&*'))
 
diff --git a/python/pyyaml/lib/yaml/scanner.py b/python/pyyaml/lib/yaml/scanner.py
index 5228fad65c..e0ed422119 100644
--- a/python/pyyaml/lib/yaml/scanner.py
+++ b/python/pyyaml/lib/yaml/scanner.py
@@ -1,4 +1,3 @@
-
 # Scanner produces tokens of the following types:
 # STREAM-START
 # STREAM-END
@@ -24,10 +23,11 @@
 # Read comments in the Scanner code for more details.
 #
 
+unichr = chr
 __all__ = ['Scanner', 'ScannerError']
 
-from error import MarkedYAMLError
-from tokens import *
+from .error import MarkedYAMLError
+from .tokens import *
 
 class ScannerError(MarkedYAMLError):
     pass
@@ -166,19 +166,19 @@ class Scanner(object):
         ch = self.peek()
 
         # Is it the end of stream?
-        if ch == u'\0':
+        if ch == '\0':
             return self.fetch_stream_end()
 
         # Is it a directive?
-        if ch == u'%' and self.check_directive():
+        if ch == '%' and self.check_directive():
             return self.fetch_directive()
 
         # Is it the document start?
-        if ch == u'-' and self.check_document_start():
+        if ch == '-' and self.check_document_start():
             return self.fetch_document_start()
 
         # Is it the document end?
-        if ch == u'.' and self.check_document_end():
+        if ch == '.' and self.check_document_end():
             return self.fetch_document_end()
 
         # TODO: support for BOM within a stream.
@@ -188,63 +188,63 @@ class Scanner(object):
         # Note: the order of the following checks is NOT significant.
 
         # Is it the flow sequence start indicator?
-        if ch == u'[':
+        if ch == '[':
             return self.fetch_flow_sequence_start()
 
         # Is it the flow mapping start indicator?
-        if ch == u'{':
+        if ch == '{':
             return self.fetch_flow_mapping_start()
 
         # Is it the flow sequence end indicator?
-        if ch == u']':
+        if ch == ']':
             return self.fetch_flow_sequence_end()
 
         # Is it the flow mapping end indicator?
-        if ch == u'}':
+        if ch == '}':
             return self.fetch_flow_mapping_end()
 
         # Is it the flow entry indicator?
-        if ch == u',':
+        if ch == ',':
             return self.fetch_flow_entry()
 
         # Is it the block entry indicator?
-        if ch == u'-' and self.check_block_entry():
+        if ch == '-' and self.check_block_entry():
             return self.fetch_block_entry()
 
         # Is it the key indicator?
-        if ch == u'?' and self.check_key():
+        if ch == '?' and self.check_key():
             return self.fetch_key()
 
         # Is it the value indicator?
-        if ch == u':' and self.check_value():
+        if ch == ':' and self.check_value():
             return self.fetch_value()
 
         # Is it an alias?
-        if ch == u'*':
+        if ch == '*':
             return self.fetch_alias()
 
         # Is it an anchor?
-        if ch == u'&':
+        if ch == '&':
             return self.fetch_anchor()
 
         # Is it a tag?
-        if ch == u'!':
+        if ch == '!':
             return self.fetch_tag()
 
         # Is it a literal scalar?
-        if ch == u'|' and not self.flow_level:
+        if ch == '|' and not self.flow_level:
             return self.fetch_literal()
 
         # Is it a folded scalar?
-        if ch == u'>' and not self.flow_level:
+        if ch == '>' and not self.flow_level:
             return self.fetch_folded()
 
         # Is it a single quoted scalar?
-        if ch == u'\'':
+        if ch == '\'':
             return self.fetch_single()
 
         # Is it a double quoted scalar?
-        if ch == u'\"':
+        if ch == '\"':
             return self.fetch_double()
 
         # It must be a plain scalar then.
@@ -692,22 +692,22 @@ class Scanner(object):
 
         # DOCUMENT-START:   ^ '---' (' '|'\n')
         if self.column == 0:
-            if self.prefix(3) == u'---'  \
-                    and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+            if self.prefix(3) == '---'  \
+                    and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
                 return True
 
     def check_document_end(self):
 
         # DOCUMENT-END:     ^ '...' (' '|'\n')
         if self.column == 0:
-            if self.prefix(3) == u'...'  \
-                    and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+            if self.prefix(3) == '...'  \
+                    and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
                 return True
 
     def check_block_entry(self):
 
         # BLOCK-ENTRY:      '-' (' '|'\n')
-        return self.peek(1) in u'\0 \t\r\n\x85\u2028\u2029'
+        return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
 
     def check_key(self):
 
@@ -717,7 +717,7 @@ class Scanner(object):
 
         # KEY(block context):   '?' (' '|'\n')
         else:
-            return self.peek(1) in u'\0 \t\r\n\x85\u2028\u2029'
+            return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
 
     def check_value(self):
 
@@ -727,7 +727,7 @@ class Scanner(object):
 
         # VALUE(block context): ':' (' '|'\n')
         else:
-            return self.peek(1) in u'\0 \t\r\n\x85\u2028\u2029'
+            return self.peek(1) in '\0 \t\r\n\x85\u2028\u2029'
 
     def check_plain(self):
 
@@ -744,9 +744,9 @@ class Scanner(object):
         # '-' character) because we want the flow context to be space
         # independent.
         ch = self.peek()
-        return ch not in u'\0 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'\"%@`'  \
-                or (self.peek(1) not in u'\0 \t\r\n\x85\u2028\u2029'
-                        and (ch == u'-' or (not self.flow_level and ch in u'?:')))
+        return ch not in '\0 \t\r\n\x85\u2028\u2029-?:,[]{}#&*!|>\'\"%@`'  \
+                or (self.peek(1) not in '\0 \t\r\n\x85\u2028\u2029'
+                        and (ch == '-' or (not self.flow_level and ch in '?:')))
 
     # Scanners.
 
@@ -770,14 +770,14 @@ class Scanner(object):
         # `unwind_indent` before issuing BLOCK-END.
         # Scanners for block, flow, and plain scalars need to be modified.
 
-        if self.index == 0 and self.peek() == u'\uFEFF':
+        if self.index == 0 and self.peek() == '\uFEFF':
             self.forward()
         found = False
         while not found:
-            while self.peek() == u' ':
+            while self.peek() == ' ':
                 self.forward()
-            if self.peek() == u'#':
-                while self.peek() not in u'\0\r\n\x85\u2028\u2029':
+            if self.peek() == '#':
+                while self.peek() not in '\0\r\n\x85\u2028\u2029':
                     self.forward()
             if self.scan_line_break():
                 if not self.flow_level:
@@ -791,15 +791,15 @@ class Scanner(object):
         self.forward()
         name = self.scan_directive_name(start_mark)
         value = None
-        if name == u'YAML':
+        if name == 'YAML':
             value = self.scan_yaml_directive_value(start_mark)
             end_mark = self.get_mark()
-        elif name == u'TAG':
+        elif name == 'TAG':
             value = self.scan_tag_directive_value(start_mark)
             end_mark = self.get_mark()
         else:
             end_mark = self.get_mark()
-            while self.peek() not in u'\0\r\n\x85\u2028\u2029':
+            while self.peek() not in '\0\r\n\x85\u2028\u2029':
                 self.forward()
         self.scan_directive_ignored_line(start_mark)
         return DirectiveToken(name, value, start_mark, end_mark)
@@ -808,8 +808,8 @@ class Scanner(object):
         # See the specification for details.
         length = 0
         ch = self.peek(length)
-        while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'    \
-                or ch in u'-_':
+        while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'    \
+                or ch in '-_':
             length += 1
             ch = self.peek(length)
         if not length:
@@ -819,7 +819,7 @@ class Scanner(object):
         value = self.prefix(length)
         self.forward(length)
         ch = self.peek()
-        if ch not in u'\0 \r\n\x85\u2028\u2029':
+        if ch not in '\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a directive", start_mark,
                     "expected alphabetic or numeric character, but found %r"
                     % ch.encode('utf-8'), self.get_mark())
@@ -827,7 +827,7 @@ class Scanner(object):
 
     def scan_yaml_directive_value(self, start_mark):
         # See the specification for details.
-        while self.peek() == u' ':
+        while self.peek() == ' ':
             self.forward()
         major = self.scan_yaml_directive_number(start_mark)
         if self.peek() != '.':
@@ -837,7 +837,7 @@ class Scanner(object):
                     self.get_mark())
         self.forward()
         minor = self.scan_yaml_directive_number(start_mark)
-        if self.peek() not in u'\0 \r\n\x85\u2028\u2029':
+        if self.peek() not in '\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a directive", start_mark,
                     "expected a digit or ' ', but found %r"
                     % self.peek().encode('utf-8'),
@@ -847,12 +847,12 @@ class Scanner(object):
     def scan_yaml_directive_number(self, start_mark):
         # See the specification for details.
         ch = self.peek()
-        if not (u'0' <= ch <= u'9'):
+        if not ('0' <= ch <= '9'):
             raise ScannerError("while scanning a directive", start_mark,
                     "expected a digit, but found %r" % ch.encode('utf-8'),
                     self.get_mark())
         length = 0
-        while u'0' <= self.peek(length) <= u'9':
+        while '0' <= self.peek(length) <= '9':
             length += 1
         value = int(self.prefix(length))
         self.forward(length)
@@ -860,10 +860,10 @@ class Scanner(object):
 
     def scan_tag_directive_value(self, start_mark):
         # See the specification for details.
-        while self.peek() == u' ':
+        while self.peek() == ' ':
             self.forward()
         handle = self.scan_tag_directive_handle(start_mark)
-        while self.peek() == u' ':
+        while self.peek() == ' ':
             self.forward()
         prefix = self.scan_tag_directive_prefix(start_mark)
         return (handle, prefix)
@@ -872,7 +872,7 @@ class Scanner(object):
         # See the specification for details.
         value = self.scan_tag_handle('directive', start_mark)
         ch = self.peek()
-        if ch != u' ':
+        if ch != ' ':
             raise ScannerError("while scanning a directive", start_mark,
                     "expected ' ', but found %r" % ch.encode('utf-8'),
                     self.get_mark())
@@ -882,7 +882,7 @@ class Scanner(object):
         # See the specification for details.
         value = self.scan_tag_uri('directive', start_mark)
         ch = self.peek()
-        if ch not in u'\0 \r\n\x85\u2028\u2029':
+        if ch not in '\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a directive", start_mark,
                     "expected ' ', but found %r" % ch.encode('utf-8'),
                     self.get_mark())
@@ -890,13 +890,13 @@ class Scanner(object):
 
     def scan_directive_ignored_line(self, start_mark):
         # See the specification for details.
-        while self.peek() == u' ':
+        while self.peek() == ' ':
             self.forward()
-        if self.peek() == u'#':
-            while self.peek() not in u'\0\r\n\x85\u2028\u2029':
+        if self.peek() == '#':
+            while self.peek() not in '\0\r\n\x85\u2028\u2029':
                 self.forward()
         ch = self.peek()
-        if ch not in u'\0\r\n\x85\u2028\u2029':
+        if ch not in '\0\r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a directive", start_mark,
                     "expected a comment or a line break, but found %r"
                         % ch.encode('utf-8'), self.get_mark())
@@ -913,15 +913,15 @@ class Scanner(object):
         # Therefore we restrict aliases to numbers and ASCII letters.
         start_mark = self.get_mark()
         indicator = self.peek()
-        if indicator == u'*':
+        if indicator == '*':
             name = 'alias'
         else:
             name = 'anchor'
         self.forward()
         length = 0
         ch = self.peek(length)
-        while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'    \
-                or ch in u'-_':
+        while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'    \
+                or ch in '-_':
             length += 1
             ch = self.peek(length)
         if not length:
@@ -931,7 +931,7 @@ class Scanner(object):
         value = self.prefix(length)
         self.forward(length)
         ch = self.peek()
-        if ch not in u'\0 \t\r\n\x85\u2028\u2029?:,]}%@`':
+        if ch not in '\0 \t\r\n\x85\u2028\u2029?:,]}%@`':
             raise ScannerError("while scanning an %s" % name, start_mark,
                     "expected alphabetic or numeric character, but found %r"
                     % ch.encode('utf-8'), self.get_mark())
@@ -942,37 +942,37 @@ class Scanner(object):
         # See the specification for details.
         start_mark = self.get_mark()
         ch = self.peek(1)
-        if ch == u'<':
+        if ch == '<':
             handle = None
             self.forward(2)
             suffix = self.scan_tag_uri('tag', start_mark)
-            if self.peek() != u'>':
+            if self.peek() != '>':
                 raise ScannerError("while parsing a tag", start_mark,
                         "expected '>', but found %r" % self.peek().encode('utf-8'),
                         self.get_mark())
             self.forward()
-        elif ch in u'\0 \t\r\n\x85\u2028\u2029':
+        elif ch in '\0 \t\r\n\x85\u2028\u2029':
             handle = None
-            suffix = u'!'
+            suffix = '!'
             self.forward()
         else:
             length = 1
             use_handle = False
-            while ch not in u'\0 \r\n\x85\u2028\u2029':
-                if ch == u'!':
+            while ch not in '\0 \r\n\x85\u2028\u2029':
+                if ch == '!':
                     use_handle = True
                     break
                 length += 1
                 ch = self.peek(length)
-            handle = u'!'
+            handle = '!'
             if use_handle:
                 handle = self.scan_tag_handle('tag', start_mark)
             else:
-                handle = u'!'
+                handle = '!'
                 self.forward()
             suffix = self.scan_tag_uri('tag', start_mark)
         ch = self.peek()
-        if ch not in u'\0 \r\n\x85\u2028\u2029':
+        if ch not in '\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a tag", start_mark,
                     "expected ' ', but found %r" % ch.encode('utf-8'),
                     self.get_mark())
@@ -1006,29 +1006,29 @@ class Scanner(object):
         else:
             indent = min_indent+increment-1
             breaks, end_mark = self.scan_block_scalar_breaks(indent)
-        line_break = u''
+        line_break = ''
 
         # Scan the inner part of the block scalar.
-        while self.column == indent and self.peek() != u'\0':
+        while self.column == indent and self.peek() != '\0':
             chunks.extend(breaks)
-            leading_non_space = self.peek() not in u' \t'
+            leading_non_space = self.peek() not in ' \t'
             length = 0
-            while self.peek(length) not in u'\0\r\n\x85\u2028\u2029':
+            while self.peek(length) not in '\0\r\n\x85\u2028\u2029':
                 length += 1
             chunks.append(self.prefix(length))
             self.forward(length)
             line_break = self.scan_line_break()
             breaks, end_mark = self.scan_block_scalar_breaks(indent)
-            if self.column == indent and self.peek() != u'\0':
+            if self.column == indent and self.peek() != '\0':
 
                 # Unfortunately, folding rules are ambiguous.
                 #
                 # This is the folding according to the specification:
                 
-                if folded and line_break == u'\n'   \
-                        and leading_non_space and self.peek() not in u' \t':
+                if folded and line_break == '\n'   \
+                        and leading_non_space and self.peek() not in ' \t':
                     if not breaks:
-                        chunks.append(u' ')
+                        chunks.append(' ')
                 else:
                     chunks.append(line_break)
                 
@@ -1053,7 +1053,7 @@ class Scanner(object):
             chunks.extend(breaks)
 
         # We are done.
-        return ScalarToken(u''.join(chunks), False, start_mark, end_mark,
+        return ScalarToken(''.join(chunks), False, start_mark, end_mark,
                 style)
 
     def scan_block_scalar_indicators(self, start_mark):
@@ -1061,21 +1061,21 @@ class Scanner(object):
         chomping = None
         increment = None
         ch = self.peek()
-        if ch in u'+-':
+        if ch in '+-':
             if ch == '+':
                 chomping = True
             else:
                 chomping = False
             self.forward()
             ch = self.peek()
-            if ch in u'0123456789':
+            if ch in '0123456789':
                 increment = int(ch)
                 if increment == 0:
                     raise ScannerError("while scanning a block scalar", start_mark,
                             "expected indentation indicator in the range 1-9, but found 0",
                             self.get_mark())
                 self.forward()
-        elif ch in u'0123456789':
+        elif ch in '0123456789':
             increment = int(ch)
             if increment == 0:
                 raise ScannerError("while scanning a block scalar", start_mark,
@@ -1083,14 +1083,14 @@ class Scanner(object):
                         self.get_mark())
             self.forward()
             ch = self.peek()
-            if ch in u'+-':
+            if ch in '+-':
                 if ch == '+':
                     chomping = True
                 else:
                     chomping = False
                 self.forward()
         ch = self.peek()
-        if ch not in u'\0 \r\n\x85\u2028\u2029':
+        if ch not in '\0 \r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a block scalar", start_mark,
                     "expected chomping or indentation indicators, but found %r"
                         % ch.encode('utf-8'), self.get_mark())
@@ -1098,13 +1098,13 @@ class Scanner(object):
 
     def scan_block_scalar_ignored_line(self, start_mark):
         # See the specification for details.
-        while self.peek() == u' ':
+        while self.peek() == ' ':
             self.forward()
-        if self.peek() == u'#':
-            while self.peek() not in u'\0\r\n\x85\u2028\u2029':
+        if self.peek() == '#':
+            while self.peek() not in '\0\r\n\x85\u2028\u2029':
                 self.forward()
         ch = self.peek()
-        if ch not in u'\0\r\n\x85\u2028\u2029':
+        if ch not in '\0\r\n\x85\u2028\u2029':
             raise ScannerError("while scanning a block scalar", start_mark,
                     "expected a comment or a line break, but found %r"
                         % ch.encode('utf-8'), self.get_mark())
@@ -1115,8 +1115,8 @@ class Scanner(object):
         chunks = []
         max_indent = 0
         end_mark = self.get_mark()
-        while self.peek() in u' \r\n\x85\u2028\u2029':
-            if self.peek() != u' ':
+        while self.peek() in ' \r\n\x85\u2028\u2029':
+            if self.peek() != ' ':
                 chunks.append(self.scan_line_break())
                 end_mark = self.get_mark()
             else:
@@ -1129,12 +1129,12 @@ class Scanner(object):
         # See the specification for details.
         chunks = []
         end_mark = self.get_mark()
-        while self.column < indent and self.peek() == u' ':
+        while self.column < indent and self.peek() == ' ':
             self.forward()
-        while self.peek() in u'\r\n\x85\u2028\u2029':
+        while self.peek() in '\r\n\x85\u2028\u2029':
             chunks.append(self.scan_line_break())
             end_mark = self.get_mark()
-            while self.column < indent and self.peek() == u' ':
+            while self.column < indent and self.peek() == ' ':
                 self.forward()
         return chunks, end_mark
 
@@ -1159,33 +1159,33 @@ class Scanner(object):
             chunks.extend(self.scan_flow_scalar_non_spaces(double, start_mark))
         self.forward()
         end_mark = self.get_mark()
-        return ScalarToken(u''.join(chunks), False, start_mark, end_mark,
+        return ScalarToken(''.join(chunks), False, start_mark, end_mark,
                 style)
 
     ESCAPE_REPLACEMENTS = {
-        u'0':   u'\0',
-        u'a':   u'\x07',
-        u'b':   u'\x08',
-        u't':   u'\x09',
-        u'\t':  u'\x09',
-        u'n':   u'\x0A',
-        u'v':   u'\x0B',
-        u'f':   u'\x0C',
-        u'r':   u'\x0D',
-        u'e':   u'\x1B',
-        u' ':   u'\x20',
-        u'\"':  u'\"',
-        u'\\':  u'\\',
-        u'N':   u'\x85',
-        u'_':   u'\xA0',
-        u'L':   u'\u2028',
-        u'P':   u'\u2029',
+        '0':   '\0',
+        'a':   '\x07',
+        'b':   '\x08',
+        't':   '\x09',
+        '\t':  '\x09',
+        'n':   '\x0A',
+        'v':   '\x0B',
+        'f':   '\x0C',
+        'r':   '\x0D',
+        'e':   '\x1B',
+        ' ':   '\x20',
+        '\"':  '\"',
+        '\\':  '\\',
+        'N':   '\x85',
+        '_':   '\xA0',
+        'L':   '\u2028',
+        'P':   '\u2029',
     }
 
     ESCAPE_CODES = {
-        u'x':   2,
-        u'u':   4,
-        u'U':   8,
+        'x':   2,
+        'u':   4,
+        'U':   8,
     }
 
     def scan_flow_scalar_non_spaces(self, double, start_mark):
@@ -1193,19 +1193,19 @@ class Scanner(object):
         chunks = []
         while True:
             length = 0
-            while self.peek(length) not in u'\'\"\\\0 \t\r\n\x85\u2028\u2029':
+            while self.peek(length) not in '\'\"\\\0 \t\r\n\x85\u2028\u2029':
                 length += 1
             if length:
                 chunks.append(self.prefix(length))
                 self.forward(length)
             ch = self.peek()
-            if not double and ch == u'\'' and self.peek(1) == u'\'':
-                chunks.append(u'\'')
+            if not double and ch == '\'' and self.peek(1) == '\'':
+                chunks.append('\'')
                 self.forward(2)
-            elif (double and ch == u'\'') or (not double and ch in u'\"\\'):
+            elif (double and ch == '\'') or (not double and ch in '\"\\'):
                 chunks.append(ch)
                 self.forward()
-            elif double and ch == u'\\':
+            elif double and ch == '\\':
                 self.forward()
                 ch = self.peek()
                 if ch in self.ESCAPE_REPLACEMENTS:
@@ -1215,14 +1215,14 @@ class Scanner(object):
                     length = self.ESCAPE_CODES[ch]
                     self.forward()
                     for k in range(length):
-                        if self.peek(k) not in u'0123456789ABCDEFabcdef':
+                        if self.peek(k) not in '0123456789ABCDEFabcdef':
                             raise ScannerError("while scanning a double-quoted scalar", start_mark,
                                     "expected escape sequence of %d hexdecimal numbers, but found %r" %
                                         (length, self.peek(k).encode('utf-8')), self.get_mark())
                     code = int(self.prefix(length), 16)
                     chunks.append(unichr(code))
                     self.forward(length)
-                elif ch in u'\r\n\x85\u2028\u2029':
+                elif ch in '\r\n\x85\u2028\u2029':
                     self.scan_line_break()
                     chunks.extend(self.scan_flow_scalar_breaks(double, start_mark))
                 else:
@@ -1235,21 +1235,21 @@ class Scanner(object):
         # See the specification for details.
         chunks = []
         length = 0
-        while self.peek(length) in u' \t':
+        while self.peek(length) in ' \t':
             length += 1
         whitespaces = self.prefix(length)
         self.forward(length)
         ch = self.peek()
-        if ch == u'\0':
+        if ch == '\0':
             raise ScannerError("while scanning a quoted scalar", start_mark,
                     "found unexpected end of stream", self.get_mark())
-        elif ch in u'\r\n\x85\u2028\u2029':
+        elif ch in '\r\n\x85\u2028\u2029':
             line_break = self.scan_line_break()
             breaks = self.scan_flow_scalar_breaks(double, start_mark)
-            if line_break != u'\n':
+            if line_break != '\n':
                 chunks.append(line_break)
             elif not breaks:
-                chunks.append(u' ')
+                chunks.append(' ')
             chunks.extend(breaks)
         else:
             chunks.append(whitespaces)
@@ -1262,13 +1262,13 @@ class Scanner(object):
             # Instead of checking indentation, we check for document
             # separators.
             prefix = self.prefix(3)
-            if (prefix == u'---' or prefix == u'...')   \
-                    and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+            if (prefix == '---' or prefix == '...')   \
+                    and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
                 raise ScannerError("while scanning a quoted scalar", start_mark,
                         "found unexpected document separator", self.get_mark())
-            while self.peek() in u' \t':
+            while self.peek() in ' \t':
                 self.forward()
-            if self.peek() in u'\r\n\x85\u2028\u2029':
+            if self.peek() in '\r\n\x85\u2028\u2029':
                 chunks.append(self.scan_line_break())
             else:
                 return chunks
@@ -1290,19 +1290,19 @@ class Scanner(object):
         spaces = []
         while True:
             length = 0
-            if self.peek() == u'#':
+            if self.peek() == '#':
                 break
             while True:
                 ch = self.peek(length)
-                if ch in u'\0 \t\r\n\x85\u2028\u2029'   \
-                        or (not self.flow_level and ch == u':' and
-                                self.peek(length+1) in u'\0 \t\r\n\x85\u2028\u2029') \
-                        or (self.flow_level and ch in u',:?[]{}'):
+                if ch in '\0 \t\r\n\x85\u2028\u2029'   \
+                        or (not self.flow_level and ch == ':' and
+                                self.peek(length+1) in '\0 \t\r\n\x85\u2028\u2029') \
+                        or (self.flow_level and ch in ',:?[]{}'):
                     break
                 length += 1
             # It's not clear what we should do with ':' in the flow context.
-            if (self.flow_level and ch == u':'
-                    and self.peek(length+1) not in u'\0 \t\r\n\x85\u2028\u2029,[]{}'):
+            if (self.flow_level and ch == ':'
+                    and self.peek(length+1) not in '\0 \t\r\n\x85\u2028\u2029,[]{}'):
                 self.forward(length)
                 raise ScannerError("while scanning a plain scalar", start_mark,
                     "found unexpected ':'", self.get_mark(),
@@ -1315,10 +1315,10 @@ class Scanner(object):
             self.forward(length)
             end_mark = self.get_mark()
             spaces = self.scan_plain_spaces(indent, start_mark)
-            if not spaces or self.peek() == u'#' \
+            if not spaces or self.peek() == '#' \
                     or (not self.flow_level and self.column < indent):
                 break
-        return ScalarToken(u''.join(chunks), True, start_mark, end_mark)
+        return ScalarToken(''.join(chunks), True, start_mark, end_mark)
 
     def scan_plain_spaces(self, indent, start_mark):
         # See the specification for details.
@@ -1326,32 +1326,32 @@ class Scanner(object):
         # We just forbid them completely. Do not use tabs in YAML!
         chunks = []
         length = 0
-        while self.peek(length) in u' ':
+        while self.peek(length) in ' ':
             length += 1
         whitespaces = self.prefix(length)
         self.forward(length)
         ch = self.peek()
-        if ch in u'\r\n\x85\u2028\u2029':
+        if ch in '\r\n\x85\u2028\u2029':
             line_break = self.scan_line_break()
             self.allow_simple_key = True
             prefix = self.prefix(3)
-            if (prefix == u'---' or prefix == u'...')   \
-                    and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+            if (prefix == '---' or prefix == '...')   \
+                    and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
                 return
             breaks = []
-            while self.peek() in u' \r\n\x85\u2028\u2029':
+            while self.peek() in ' \r\n\x85\u2028\u2029':
                 if self.peek() == ' ':
                     self.forward()
                 else:
                     breaks.append(self.scan_line_break())
                     prefix = self.prefix(3)
-                    if (prefix == u'---' or prefix == u'...')   \
-                            and self.peek(3) in u'\0 \t\r\n\x85\u2028\u2029':
+                    if (prefix == '---' or prefix == '...')   \
+                            and self.peek(3) in '\0 \t\r\n\x85\u2028\u2029':
                         return
-            if line_break != u'\n':
+            if line_break != '\n':
                 chunks.append(line_break)
             elif not breaks:
-                chunks.append(u' ')
+                chunks.append(' ')
             chunks.extend(breaks)
         elif whitespaces:
             chunks.append(whitespaces)
@@ -1362,18 +1362,18 @@ class Scanner(object):
         # For some strange reasons, the specification does not allow '_' in
         # tag handles. I have allowed it anyway.
         ch = self.peek()
-        if ch != u'!':
+        if ch != '!':
             raise ScannerError("while scanning a %s" % name, start_mark,
                     "expected '!', but found %r" % ch.encode('utf-8'),
                     self.get_mark())
         length = 1
         ch = self.peek(length)
-        if ch != u' ':
-            while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'    \
-                    or ch in u'-_':
+        if ch != ' ':
+            while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'    \
+                    or ch in '-_':
                 length += 1
                 ch = self.peek(length)
-            if ch != u'!':
+            if ch != '!':
                 self.forward(length)
                 raise ScannerError("while scanning a %s" % name, start_mark,
                         "expected '!', but found %r" % ch.encode('utf-8'),
@@ -1389,9 +1389,9 @@ class Scanner(object):
         chunks = []
         length = 0
         ch = self.peek(length)
-        while u'0' <= ch <= u'9' or u'A' <= ch <= u'Z' or u'a' <= ch <= u'z'    \
-                or ch in u'-;/?:@&=+$,_.!~*\'()[]%':
-            if ch == u'%':
+        while '0' <= ch <= '9' or 'A' <= ch <= 'Z' or 'a' <= ch <= 'z'    \
+                or ch in '-;/?:@&=+$,_.!~*\'()[]%':
+            if ch == '%':
                 chunks.append(self.prefix(length))
                 self.forward(length)
                 length = 0
@@ -1407,24 +1407,24 @@ class Scanner(object):
             raise ScannerError("while parsing a %s" % name, start_mark,
                     "expected URI, but found %r" % ch.encode('utf-8'),
                     self.get_mark())
-        return u''.join(chunks)
+        return ''.join(chunks)
 
     def scan_uri_escapes(self, name, start_mark):
         # See the specification for details.
         bytes = []
         mark = self.get_mark()
-        while self.peek() == u'%':
+        while self.peek() == '%':
             self.forward()
             for k in range(2):
-                if self.peek(k) not in u'0123456789ABCDEFabcdef':
+                if self.peek(k) not in '0123456789ABCDEFabcdef':
                     raise ScannerError("while scanning a %s" % name, start_mark,
                             "expected URI escape sequence of 2 hexdecimal numbers, but found %r" %
                                 (self.peek(k).encode('utf-8')), self.get_mark())
             bytes.append(chr(int(self.prefix(2), 16)))
             self.forward(2)
         try:
-            value = unicode(''.join(bytes), 'utf-8')
-        except UnicodeDecodeError, exc:
+            value = str(''.join(bytes), 'utf-8')
+        except UnicodeDecodeError as exc:
             raise ScannerError("while scanning a %s" % name, start_mark, str(exc), mark)
         return value
 
@@ -1438,16 +1438,16 @@ class Scanner(object):
         #   '\u2029     :   '\u2029'
         #   default     :   ''
         ch = self.peek()
-        if ch in u'\r\n\x85':
-            if self.prefix(2) == u'\r\n':
+        if ch in '\r\n\x85':
+            if self.prefix(2) == '\r\n':
                 self.forward(2)
             else:
                 self.forward()
-            return u'\n'
-        elif ch in u'\u2028\u2029':
+            return '\n'
+        elif ch in '\u2028\u2029':
             self.forward()
             return ch
-        return u''
+        return ''
 
 #try:
 #    import psyco
diff --git a/python/pyyaml/lib/yaml/serializer.py b/python/pyyaml/lib/yaml/serializer.py
index 0bf1e96dc1..89eb64e5eb 100644
--- a/python/pyyaml/lib/yaml/serializer.py
+++ b/python/pyyaml/lib/yaml/serializer.py
@@ -1,16 +1,15 @@
-
 __all__ = ['Serializer', 'SerializerError']
 
-from error import YAMLError
-from events import *
-from nodes import *
+from .error import YAMLError
+from .events import *
+from .nodes import *
 
 class SerializerError(YAMLError):
     pass
 
-class Serializer(object):
+class Serializer:
 
-    ANCHOR_TEMPLATE = u'id%03d'
+    ANCHOR_TEMPLATE = 'id%03d'
 
     def __init__(self, encoding=None,
             explicit_start=None, explicit_end=None, version=None, tags=None):
diff --git a/python/pyyaml/lib/yaml/tokens.py b/python/pyyaml/lib/yaml/tokens.py
index 4d0b48a394..93f5700e28 100644
--- a/python/pyyaml/lib/yaml/tokens.py
+++ b/python/pyyaml/lib/yaml/tokens.py
@@ -1,5 +1,4 @@
-
-class Token(object):
+class Token:
     def __init__(self, start_mark, end_mark):
         self.start_mark = start_mark
         self.end_mark = end_mark
@@ -7,9 +6,9 @@ class Token(object):
         attributes = [key for key in self.__dict__
                 if not key.endswith('_mark')]
         attributes.sort()
-        arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
+        arguments = ', '.join(['{}={!r}'.format(key, getattr(self, key))
                 for key in attributes])
-        return '%s(%s)' % (self.__class__.__name__, arguments)
+        return '{}({})'.format(self.__class__.__name__, arguments)
 
 #class BOMToken(Token):
 #    id = '<byte order mark>'
diff --git a/python/pyyaml/lib3/yaml/__init__.py b/python/pyyaml/lib3/yaml/__init__.py
index a5e20f94d2..b3e4c7ce06 100644
--- a/python/pyyaml/lib3/yaml/__init__.py
+++ b/python/pyyaml/lib3/yaml/__init__.py
@@ -1,4 +1,3 @@
-
 from .error import *
 
 from .tokens import *
@@ -276,7 +275,7 @@ class YAMLObjectMetaclass(type):
     The metaclass for YAMLObject.
     """
     def __init__(cls, name, bases, kwds):
-        super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
+        super().__init__(name, bases, kwds)
         if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
             cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
             cls.yaml_dumper.add_representer(cls, cls.to_yaml)
diff --git a/python/pyyaml/lib3/yaml/composer.py b/python/pyyaml/lib3/yaml/composer.py
index d5c6a7acd9..5de30b4758 100644
--- a/python/pyyaml/lib3/yaml/composer.py
+++ b/python/pyyaml/lib3/yaml/composer.py
@@ -1,4 +1,3 @@
-
 __all__ = ['Composer', 'ComposerError']
 
 from .error import MarkedYAMLError
diff --git a/python/pyyaml/lib3/yaml/constructor.py b/python/pyyaml/lib3/yaml/constructor.py
index 981543aebb..7d6482df38 100644
--- a/python/pyyaml/lib3/yaml/constructor.py
+++ b/python/pyyaml/lib3/yaml/constructor.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseConstructor', 'SafeConstructor', 'Constructor',
     'ConstructorError']
 
@@ -123,7 +122,7 @@ class BaseConstructor:
         mapping = {}
         for key_node, value_node in node.value:
             key = self.construct_object(key_node, deep=deep)
-            if not isinstance(key, collections.Hashable):
+            if not isinstance(key, collections.abc.Hashable):
                 raise ConstructorError("while constructing a mapping", node.start_mark,
                         "found unhashable key", key_node.start_mark)
             value = self.construct_object(value_node, deep=deep)
@@ -505,7 +504,7 @@ class Constructor(SafeConstructor):
             __import__(name)
         except ImportError as exc:
             raise ConstructorError("while constructing a Python module", mark,
-                    "cannot find module %r (%s)" % (name, exc), mark)
+                    "cannot find module {!r} ({})".format(name, exc), mark)
         return sys.modules[name]
 
     def find_python_name(self, name, mark):
@@ -521,7 +520,7 @@ class Constructor(SafeConstructor):
             __import__(module_name)
         except ImportError as exc:
             raise ConstructorError("while constructing a Python object", mark,
-                    "cannot find module %r (%s)" % (module_name, exc), mark)
+                    "cannot find module {!r} ({})".format(module_name, exc), mark)
         module = sys.modules[module_name]
         if not hasattr(module, object_name):
             raise ConstructorError("while constructing a Python object", mark,
diff --git a/python/pyyaml/lib3/yaml/cyaml.py b/python/pyyaml/lib3/yaml/cyaml.py
index d5cb87e994..0baa920d40 100644
--- a/python/pyyaml/lib3/yaml/cyaml.py
+++ b/python/pyyaml/lib3/yaml/cyaml.py
@@ -1,4 +1,3 @@
-
 __all__ = ['CBaseLoader', 'CSafeLoader', 'CLoader',
         'CBaseDumper', 'CSafeDumper', 'CDumper']
 
diff --git a/python/pyyaml/lib3/yaml/dumper.py b/python/pyyaml/lib3/yaml/dumper.py
index 0b69128771..dfd8c7cf36 100644
--- a/python/pyyaml/lib3/yaml/dumper.py
+++ b/python/pyyaml/lib3/yaml/dumper.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseDumper', 'SafeDumper', 'Dumper']
 
 from .emitter import *
diff --git a/python/pyyaml/lib3/yaml/emitter.py b/python/pyyaml/lib3/yaml/emitter.py
index 34cb145a5f..c0bfcf1f85 100644
--- a/python/pyyaml/lib3/yaml/emitter.py
+++ b/python/pyyaml/lib3/yaml/emitter.py
@@ -1,4 +1,3 @@
-
 # Emitter expects events obeying the following grammar:
 # stream ::= STREAM-START document* STREAM-END
 # document ::= DOCUMENT-START node DOCUMENT-END
@@ -609,7 +608,7 @@ class Emitter:
             chunks.append(suffix[start:end])
         suffix_text = ''.join(chunks)
         if handle:
-            return '%s%s' % (handle, suffix_text)
+            return '{}{}'.format(handle, suffix_text)
         else:
             return '!<%s>' % suffix_text
 
@@ -842,7 +841,7 @@ class Emitter:
         self.write_line_break()
 
     def write_tag_directive(self, handle_text, prefix_text):
-        data = '%%TAG %s %s' % (handle_text, prefix_text)
+        data = '%TAG {} {}'.format(handle_text, prefix_text)
         if self.encoding:
             data = data.encode(self.encoding)
         self.stream.write(data)
diff --git a/python/pyyaml/lib3/yaml/error.py b/python/pyyaml/lib3/yaml/error.py
index b796b4dc51..10f8835421 100644
--- a/python/pyyaml/lib3/yaml/error.py
+++ b/python/pyyaml/lib3/yaml/error.py
@@ -1,4 +1,3 @@
-
 __all__ = ['Mark', 'YAMLError', 'MarkedYAMLError']
 
 class Mark:
diff --git a/python/pyyaml/lib3/yaml/events.py b/python/pyyaml/lib3/yaml/events.py
index f79ad389cb..e54499400a 100644
--- a/python/pyyaml/lib3/yaml/events.py
+++ b/python/pyyaml/lib3/yaml/events.py
@@ -1,16 +1,15 @@
-
 # Abstract classes.
 
-class Event(object):
+class Event:
     def __init__(self, start_mark=None, end_mark=None):
         self.start_mark = start_mark
         self.end_mark = end_mark
     def __repr__(self):
         attributes = [key for key in ['anchor', 'tag', 'implicit', 'value']
                 if hasattr(self, key)]
-        arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
+        arguments = ', '.join(['{}={!r}'.format(key, getattr(self, key))
                 for key in attributes])
-        return '%s(%s)' % (self.__class__.__name__, arguments)
+        return '{}({})'.format(self.__class__.__name__, arguments)
 
 class NodeEvent(Event):
     def __init__(self, anchor, start_mark=None, end_mark=None):
diff --git a/python/pyyaml/lib3/yaml/loader.py b/python/pyyaml/lib3/yaml/loader.py
index 08c8f01b34..559275b02a 100644
--- a/python/pyyaml/lib3/yaml/loader.py
+++ b/python/pyyaml/lib3/yaml/loader.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseLoader', 'SafeLoader', 'Loader']
 
 from .reader import *
diff --git a/python/pyyaml/lib3/yaml/nodes.py b/python/pyyaml/lib3/yaml/nodes.py
index c4f070c41e..c9a20df12a 100644
--- a/python/pyyaml/lib3/yaml/nodes.py
+++ b/python/pyyaml/lib3/yaml/nodes.py
@@ -1,5 +1,4 @@
-
-class Node(object):
+class Node:
     def __init__(self, tag, value, start_mark, end_mark):
         self.tag = tag
         self.value = value
@@ -20,7 +19,7 @@ class Node(object):
         #    else:
         #        value = repr(value)
         value = repr(value)
-        return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value)
+        return '{}(tag={!r}, value={})'.format(self.__class__.__name__, self.tag, value)
 
 class ScalarNode(Node):
     id = 'scalar'
diff --git a/python/pyyaml/lib3/yaml/parser.py b/python/pyyaml/lib3/yaml/parser.py
index 13a5995d29..086838d1b2 100644
--- a/python/pyyaml/lib3/yaml/parser.py
+++ b/python/pyyaml/lib3/yaml/parser.py
@@ -1,4 +1,3 @@
-
 # The following YAML grammar is LL(1) and is parsed by a recursive descent
 # parser.
 #
diff --git a/python/pyyaml/lib3/yaml/reader.py b/python/pyyaml/lib3/yaml/reader.py
index f70e920f44..f4f64d084e 100644
--- a/python/pyyaml/lib3/yaml/reader.py
+++ b/python/pyyaml/lib3/yaml/reader.py
@@ -42,7 +42,7 @@ class ReaderError(YAMLError):
                     % (self.character, self.reason,
                             self.name, self.position)
 
-class Reader(object):
+class Reader:
     # Reader:
     # - determines the data encoding and converts it to a unicode string,
     # - checks if characters are in allowed range,
diff --git a/python/pyyaml/lib3/yaml/representer.py b/python/pyyaml/lib3/yaml/representer.py
index 67cd6fd25e..513c0b1187 100644
--- a/python/pyyaml/lib3/yaml/representer.py
+++ b/python/pyyaml/lib3/yaml/representer.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseRepresenter', 'SafeRepresenter', 'Representer',
     'RepresenterError']
 
@@ -273,16 +272,16 @@ class Representer(SafeRepresenter):
         elif data.real == 0.0:
             data = '%rj' % data.imag
         elif data.imag > 0:
-            data = '%r+%rj' % (data.real, data.imag)
+            data = '{!r}+{!r}j'.format(data.real, data.imag)
         else:
-            data = '%r%rj' % (data.real, data.imag)
+            data = '{!r}{!r}j'.format(data.real, data.imag)
         return self.represent_scalar('tag:yaml.org,2002:python/complex', data)
 
     def represent_tuple(self, data):
         return self.represent_sequence('tag:yaml.org,2002:python/tuple', data)
 
     def represent_name(self, data):
-        name = '%s.%s' % (data.__module__, data.__name__)
+        name = '{}.{}'.format(data.__module__, data.__name__)
         return self.represent_scalar('tag:yaml.org,2002:python/name:'+name, '')
 
     def represent_module(self, data):
@@ -332,7 +331,7 @@ class Representer(SafeRepresenter):
         else:
             tag = 'tag:yaml.org,2002:python/object/apply:'
             newobj = False
-        function_name = '%s.%s' % (function.__module__, function.__name__)
+        function_name = '{}.{}'.format(function.__module__, function.__name__)
         if not args and not listitems and not dictitems \
                 and isinstance(state, dict) and newobj:
             return self.represent_mapping(
diff --git a/python/pyyaml/lib3/yaml/resolver.py b/python/pyyaml/lib3/yaml/resolver.py
index 0eece25821..3df59e3346 100644
--- a/python/pyyaml/lib3/yaml/resolver.py
+++ b/python/pyyaml/lib3/yaml/resolver.py
@@ -1,4 +1,3 @@
-
 __all__ = ['BaseResolver', 'Resolver']
 
 from .error import *
diff --git a/python/pyyaml/lib3/yaml/scanner.py b/python/pyyaml/lib3/yaml/scanner.py
index 494d975ba6..695b14bb05 100644
--- a/python/pyyaml/lib3/yaml/scanner.py
+++ b/python/pyyaml/lib3/yaml/scanner.py
@@ -1,4 +1,3 @@
-
 # Scanner produces tokens of the following types:
 # STREAM-START
 # STREAM-END
diff --git a/python/pyyaml/lib3/yaml/serializer.py b/python/pyyaml/lib3/yaml/serializer.py
index fe911e67ae..89eb64e5eb 100644
--- a/python/pyyaml/lib3/yaml/serializer.py
+++ b/python/pyyaml/lib3/yaml/serializer.py
@@ -1,4 +1,3 @@
-
 __all__ = ['Serializer', 'SerializerError']
 
 from .error import YAMLError
diff --git a/python/pyyaml/lib3/yaml/tokens.py b/python/pyyaml/lib3/yaml/tokens.py
index 4d0b48a394..93f5700e28 100644
--- a/python/pyyaml/lib3/yaml/tokens.py
+++ b/python/pyyaml/lib3/yaml/tokens.py
@@ -1,5 +1,4 @@
-
-class Token(object):
+class Token:
     def __init__(self, start_mark, end_mark):
         self.start_mark = start_mark
         self.end_mark = end_mark
@@ -7,9 +6,9 @@ class Token(object):
         attributes = [key for key in self.__dict__
                 if not key.endswith('_mark')]
         attributes.sort()
-        arguments = ', '.join(['%s=%r' % (key, getattr(self, key))
+        arguments = ', '.join(['{}={!r}'.format(key, getattr(self, key))
                 for key in attributes])
-        return '%s(%s)' % (self.__class__.__name__, arguments)
+        return '{}({})'.format(self.__class__.__name__, arguments)
 
 #class BOMToken(Token):
 #    id = '<byte order mark>'
diff --git a/python/pyyaml/setup.py b/python/pyyaml/setup.py
index 727c3e06ea..d08d0713d0 100644
--- a/python/pyyaml/setup.py
+++ b/python/pyyaml/setup.py
@@ -1,4 +1,3 @@
-
 NAME = 'PyYAML'
 VERSION = '3.11'
 DESCRIPTION = "YAML parser and emitter for Python"
@@ -19,7 +18,7 @@ AUTHOR_EMAIL = 'xi@resolvent.net'
 LICENSE = "MIT"
 PLATFORMS = "Any"
 URL = "http://pyyaml.org/wiki/PyYAML"
-DOWNLOAD_URL = "http://pyyaml.org/download/pyyaml/%s-%s.tar.gz" % (NAME, VERSION)
+DOWNLOAD_URL = "http://pyyaml.org/download/pyyaml/{}-{}.tar.gz".format(NAME, VERSION)
 CLASSIFIERS = [
     "Development Status :: 5 - Production/Stable",
     "Intended Audience :: Developers",
@@ -75,22 +74,6 @@ if 'setuptools.extension' in sys.modules:
     sys.modules['distutils.command.build_ext'].Extension = _Extension
 
 with_pyrex = None
-if sys.version_info[0] < 3:
-    try:
-        from Cython.Distutils.extension import Extension as _Extension
-        from Cython.Distutils import build_ext as _build_ext
-        with_pyrex = 'cython'
-    except ImportError:
-        try:
-            # Pyrex cannot build _yaml.c at the moment,
-            # but it may get fixed eventually.
-            from Pyrex.Distutils import Extension as _Extension
-            from Pyrex.Distutils import build_ext as _build_ext
-            with_pyrex = 'pyrex'
-        except ImportError:
-            pass
-
-
 class Distribution(_Distribution):
 
     def __init__(self, attrs=None):
@@ -187,7 +170,7 @@ class build_ext(_build_ext):
                 filenames.append(filename)
                 base = os.path.splitext(filename)[0]
                 for ext in ['c', 'h', 'pyx', 'pxd']:
-                    filename = '%s.%s' % (base, ext)
+                    filename = '{}.{}'.format(base, ext)
                     if filename not in filenames and os.path.isfile(filename):
                         filenames.append(filename)
         return filenames
@@ -303,10 +286,7 @@ class test(Command):
         build_cmd = self.get_finalized_command('build')
         build_cmd.run()
         sys.path.insert(0, build_cmd.build_lib)
-        if sys.version_info[0] < 3:
-            sys.path.insert(0, 'tests/lib')
-        else:
-            sys.path.insert(0, 'tests/lib3')
+        sys.path.insert(0, 'tests/lib3')
         import test_all
         test_all.main([])
 
diff --git a/python/requests/requests/__init__.py b/python/requests/requests/__init__.py
index bd5b5b9749..c438937716 100644
--- a/python/requests/requests/__init__.py
+++ b/python/requests/requests/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 #   __
 #  /__)  _  _     _   _ _/   _
 # / (   (- (/ (/ (- _)  /  _)
diff --git a/python/requests/requests/adapters.py b/python/requests/requests/adapters.py
index 6266d5be30..2c785296d8 100644
--- a/python/requests/requests/adapters.py
+++ b/python/requests/requests/adapters.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.adapters
 ~~~~~~~~~~~~~~~~~
@@ -16,7 +14,7 @@ from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
 from .packages.urllib3.response import HTTPResponse
 from .packages.urllib3.util import Timeout as TimeoutSauce
 from .packages.urllib3.util.retry import Retry
-from .compat import urlparse, basestring
+from .compat import urlparse
 from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
                     prepend_scheme_if_needed, get_auth_from_url, urldefragauth,
                     select_proxy)
@@ -42,11 +40,11 @@ DEFAULT_RETRIES = 0
 DEFAULT_POOL_TIMEOUT = None
 
 
-class BaseAdapter(object):
+class BaseAdapter:
     """The Base Transport Adapter"""
 
     def __init__(self):
-        super(BaseAdapter, self).__init__()
+        super().__init__()
 
     def send(self):
         raise NotImplementedError
@@ -94,7 +92,7 @@ class HTTPAdapter(BaseAdapter):
         self.config = {}
         self.proxy_manager = {}
 
-        super(HTTPAdapter, self).__init__()
+        super().__init__()
 
         self._pool_connections = pool_connections
         self._pool_maxsize = pool_maxsize
@@ -103,8 +101,8 @@ class HTTPAdapter(BaseAdapter):
         self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
 
     def __getstate__(self):
-        return dict((attr, getattr(self, attr, None)) for attr in
-                    self.__attrs__)
+        return {attr: getattr(self, attr, None) for attr in
+                    self.__attrs__}
 
     def __setstate__(self, state):
         # Can't handle by adding 'proxy_manager' to self.__attrs__ because
@@ -197,7 +195,7 @@ class HTTPAdapter(BaseAdapter):
             conn.ca_cert_dir = None
 
         if cert:
-            if not isinstance(cert, basestring):
+            if not isinstance(cert, str):
                 conn.cert_file = cert[0]
                 conn.key_file = cert[1]
             else:
@@ -354,7 +352,7 @@ class HTTPAdapter(BaseAdapter):
                 timeout = TimeoutSauce(connect=connect, read=read)
             except ValueError as e:
                 # this may raise a string formatting error.
-                err = ("Invalid timeout {0}. Pass a (connect, read) "
+                err = ("Invalid timeout {}. Pass a (connect, read) "
                        "timeout tuple, or a single float to set "
                        "both timeouts to the same value".format(timeout))
                 raise ValueError(err)
@@ -422,7 +420,7 @@ class HTTPAdapter(BaseAdapter):
                     low_conn.close()
                     raise
 
-        except (ProtocolError, socket.error) as err:
+        except (ProtocolError, OSError) as err:
             raise ConnectionError(err, request=request)
 
         except MaxRetryError as e:
diff --git a/python/requests/requests/api.py b/python/requests/requests/api.py
index b21a1a4fa7..b43fc55d60 100644
--- a/python/requests/requests/api.py
+++ b/python/requests/requests/api.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.api
 ~~~~~~~~~~~~
@@ -54,7 +52,7 @@ def request(method, url, **kwargs):
 
 
 def get(url, params=None, **kwargs):
-    """Sends a GET request.
+    r"""Sends a GET request.
 
     :param url: URL for the new :class:`Request` object.
     :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
@@ -68,7 +66,7 @@ def get(url, params=None, **kwargs):
 
 
 def options(url, **kwargs):
-    """Sends a OPTIONS request.
+    r"""Sends a OPTIONS request.
 
     :param url: URL for the new :class:`Request` object.
     :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -81,7 +79,7 @@ def options(url, **kwargs):
 
 
 def head(url, **kwargs):
-    """Sends a HEAD request.
+    r"""Sends a HEAD request.
 
     :param url: URL for the new :class:`Request` object.
     :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -94,7 +92,7 @@ def head(url, **kwargs):
 
 
 def post(url, data=None, json=None, **kwargs):
-    """Sends a POST request.
+    r"""Sends a POST request.
 
     :param url: URL for the new :class:`Request` object.
     :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -108,7 +106,7 @@ def post(url, data=None, json=None, **kwargs):
 
 
 def put(url, data=None, **kwargs):
-    """Sends a PUT request.
+    r"""Sends a PUT request.
 
     :param url: URL for the new :class:`Request` object.
     :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -121,7 +119,7 @@ def put(url, data=None, **kwargs):
 
 
 def patch(url, data=None, **kwargs):
-    """Sends a PATCH request.
+    r"""Sends a PATCH request.
 
     :param url: URL for the new :class:`Request` object.
     :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -134,7 +132,7 @@ def patch(url, data=None, **kwargs):
 
 
 def delete(url, **kwargs):
-    """Sends a DELETE request.
+    r"""Sends a DELETE request.
 
     :param url: URL for the new :class:`Request` object.
     :param \*\*kwargs: Optional arguments that ``request`` takes.
diff --git a/python/requests/requests/auth.py b/python/requests/requests/auth.py
index 2af55fb5e6..19393872eb 100644
--- a/python/requests/requests/auth.py
+++ b/python/requests/requests/auth.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.auth
 ~~~~~~~~~~~~~
@@ -28,13 +26,13 @@ def _basic_auth_str(username, password):
     """Returns a Basic Auth string."""
 
     authstr = 'Basic ' + to_native_string(
-        b64encode(('%s:%s' % (username, password)).encode('latin1')).strip()
+        b64encode(('{}:{}'.format(username, password)).encode('latin1')).strip()
     )
 
     return authstr
 
 
-class AuthBase(object):
+class AuthBase:
     """Base class that all auth implementations derive from"""
 
     def __call__(self, r):
@@ -103,7 +101,7 @@ class HTTPDigestAuth(AuthBase):
                 return hashlib.sha1(x).hexdigest()
             hash_utf8 = sha_utf8
 
-        KD = lambda s, d: hash_utf8("%s:%s" % (s, d))
+        KD = lambda s, d: hash_utf8("{}:{}".format(s, d))
 
         if hash_utf8 is None:
             return None
@@ -116,8 +114,8 @@ class HTTPDigestAuth(AuthBase):
         if p_parsed.query:
             path += '?' + p_parsed.query
 
-        A1 = '%s:%s:%s' % (self.username, realm, self.password)
-        A2 = '%s:%s' % (method, path)
+        A1 = '{}:{}:{}'.format(self.username, realm, self.password)
+        A2 = '{}:{}'.format(method, path)
 
         HA1 = hash_utf8(A1)
         HA2 = hash_utf8(A2)
@@ -134,12 +132,12 @@ class HTTPDigestAuth(AuthBase):
 
         cnonce = (hashlib.sha1(s).hexdigest()[:16])
         if _algorithm == 'MD5-SESS':
-            HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce))
+            HA1 = hash_utf8('{}:{}:{}'.format(HA1, nonce, cnonce))
 
         if not qop:
-            respdig = KD(HA1, "%s:%s" % (nonce, HA2))
+            respdig = KD(HA1, "{}:{}".format(nonce, HA2))
         elif qop == 'auth' or 'auth' in qop.split(','):
-            noncebit = "%s:%s:%s:%s:%s" % (
+            noncebit = "{}:{}:{}:{}:{}".format(
                 nonce, ncvalue, cnonce, 'auth', HA2
                 )
             respdig = KD(HA1, noncebit)
@@ -159,7 +157,7 @@ class HTTPDigestAuth(AuthBase):
         if entdig:
             base += ', digest="%s"' % entdig
         if qop:
-            base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce)
+            base += ', qop="auth", nc={}, cnonce="{}"'.format(ncvalue, cnonce)
 
         return 'Digest %s' % (base)
 
diff --git a/python/requests/requests/certs.py b/python/requests/requests/certs.py
index 07e6475070..91655f2744 100644
--- a/python/requests/requests/certs.py
+++ b/python/requests/requests/certs.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 """
 certs.py
@@ -11,6 +10,7 @@ If you are packaging Requests, e.g., for a Linux distribution or a managed
 environment, you can change the definition of where() to return a separately
 packaged CA bundle.
 """
+from __future__ import print_function
 import os.path
 
 try:
@@ -22,4 +22,4 @@ except ImportError:
         return os.path.join(os.path.dirname(__file__), 'cacert.pem')
 
 if __name__ == '__main__':
-    print(where())
+    print((where()))
diff --git a/python/requests/requests/compat.py b/python/requests/requests/compat.py
index 70edff7849..0bc47c55f0 100644
--- a/python/requests/requests/compat.py
+++ b/python/requests/requests/compat.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 pythoncompat
 """
@@ -33,19 +31,19 @@ except (ImportError, SyntaxError):
 # ---------
 
 if is_py2:
-    from urllib import quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, proxy_bypass
-    from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag
+    from urllib.parse import quote, unquote, quote_plus, unquote_plus, urlencode
+    from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urldefrag
     from urllib2 import parse_http_list
-    import cookielib
-    from Cookie import Morsel
+    import six.moves.http_cookiejar
+    from six.moves.http_cookies import Morsel
     from StringIO import StringIO
     from .packages.urllib3.packages.ordered_dict import OrderedDict
 
     builtin_str = str
     bytes = str
-    str = unicode
-    basestring = basestring
-    numeric_types = (int, long, float)
+    str = str
+    str = str
+    numeric_types = (int, int, float)
 
 elif is_py3:
     from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag
@@ -58,5 +56,5 @@ elif is_py3:
     builtin_str = str
     str = str
     bytes = bytes
-    basestring = (str, bytes)
+    str = (str, bytes)
     numeric_types = (int, float)
diff --git a/python/requests/requests/cookies.py b/python/requests/requests/cookies.py
index b85fd2b626..c9991570a0 100644
--- a/python/requests/requests/cookies.py
+++ b/python/requests/requests/cookies.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 Compatibility code to be able to use `cookielib.CookieJar` with requests.
 
@@ -20,7 +18,7 @@ except ImportError:
     import dummy_threading as threading
 
 
-class MockRequest(object):
+class MockRequest:
     """Wraps a `requests.Request` to mimic a `urllib2.Request`.
 
     The code in `cookielib.CookieJar` expects this interface in order to correctly
@@ -92,7 +90,7 @@ class MockRequest(object):
         return self.get_host()
 
 
-class MockResponse(object):
+class MockResponse:
     """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
 
     ...what? Basically, expose the parsed HTTP headers from the server response
@@ -161,7 +159,7 @@ class CookieConflictError(RuntimeError):
     Use .get and .set and include domain and path args in order to be more specific."""
 
 
-class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
+class RequestsCookieJar(cookielib.CookieJar, collections.abc.MutableMapping):
     """Compatibility class; is a cookielib.CookieJar, but exposes a dict
     interface.
 
@@ -214,7 +212,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
     def keys(self):
         """Dict-like keys() that returns a list of names of cookies from the
         jar. See values() and items()."""
-        return list(self.iterkeys())
+        return list(self.keys())
 
     def itervalues(self):
         """Dict-like itervalues() that returns an iterator of values of cookies
@@ -225,7 +223,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
     def values(self):
         """Dict-like values() that returns a list of values of cookies from the
         jar. See keys() and items()."""
-        return list(self.itervalues())
+        return list(self.values())
 
     def iteritems(self):
         """Dict-like iteritems() that returns an iterator of name-value tuples
@@ -238,7 +236,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
         jar. See keys() and values(). Allows client-code to call
         ``dict(RequestsCookieJar)`` and get a vanilla python dict of key value
         pairs."""
-        return list(self.iteritems())
+        return list(self.items())
 
     def list_domains(self):
         """Utility method to list all the domains in the jar."""
@@ -301,7 +299,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
     def set_cookie(self, cookie, *args, **kwargs):
         if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'):
             cookie.value = cookie.value.replace('\\"', '')
-        return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs)
+        return super().set_cookie(cookie, *args, **kwargs)
 
     def update(self, other):
         """Updates this jar with cookies from another CookieJar or dict-like"""
@@ -309,7 +307,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
             for cookie in other:
                 self.set_cookie(copy.copy(cookie))
         else:
-            super(RequestsCookieJar, self).update(other)
+            super().update(other)
 
     def _find(self, name, domain=None, path=None):
         """Requests uses this method internally to get cookie values. Takes as
@@ -323,7 +321,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
                     if path is None or cookie.path == path:
                         return cookie.value
 
-        raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
+        raise KeyError('name={!r}, domain={!r}, path={!r}'.format(name, domain, path))
 
     def _find_no_duplicates(self, name, domain=None, path=None):
         """Both ``__get_item__`` and ``get`` call this function: it's never
@@ -342,7 +340,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
 
         if toReturn:
             return toReturn
-        raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
+        raise KeyError('name={!r}, domain={!r}, path={!r}'.format(name, domain, path))
 
     def __getstate__(self):
         """Unlike a normal CookieJar, this class is pickleable."""
diff --git a/python/requests/requests/exceptions.py b/python/requests/requests/exceptions.py
index ba0b910e31..9ba622e522 100644
--- a/python/requests/requests/exceptions.py
+++ b/python/requests/requests/exceptions.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.exceptions
 ~~~~~~~~~~~~~~~~~~~
@@ -24,7 +22,7 @@ class RequestException(IOError):
         if (response is not None and not self.request and
                 hasattr(response, 'request')):
             self.request = self.response.request
-        super(RequestException, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
 
 
 class HTTPError(RequestException):
diff --git a/python/requests/requests/hooks.py b/python/requests/requests/hooks.py
index 9da94366d7..274929344e 100644
--- a/python/requests/requests/hooks.py
+++ b/python/requests/requests/hooks.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.hooks
 ~~~~~~~~~~~~~~
@@ -15,7 +13,7 @@ Available hooks:
 HOOKS = ['response']
 
 def default_hooks():
-    return dict((event, []) for event in HOOKS)
+    return {event: [] for event in HOOKS}
 
 # TODO: response is the only one
 
diff --git a/python/requests/requests/models.py b/python/requests/requests/models.py
index 4bcbc5484a..36b0c1a632 100644
--- a/python/requests/requests/models.py
+++ b/python/requests/requests/models.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.models
 ~~~~~~~~~~~~~~~
@@ -30,7 +28,7 @@ from .utils import (
     iter_slices, guess_json_utf, super_len, to_native_string)
 from .compat import (
     cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
-    is_py2, chardet, builtin_str, basestring)
+    is_py2, chardet, builtin_str, str)
 from .compat import json as complexjson
 from .status_codes import codes
 
@@ -49,7 +47,7 @@ CONTENT_CHUNK_SIZE = 10 * 1024
 ITER_CHUNK_SIZE = 512
 
 
-class RequestEncodingMixin(object):
+class RequestEncodingMixin:
     @property
     def path_url(self):
         """Build the path URL to use."""
@@ -87,7 +85,7 @@ class RequestEncodingMixin(object):
         elif hasattr(data, '__iter__'):
             result = []
             for k, vs in to_key_val_list(data):
-                if isinstance(vs, basestring) or not hasattr(vs, '__iter__'):
+                if isinstance(vs, str) or not hasattr(vs, '__iter__'):
                     vs = [vs]
                 for v in vs:
                     if v is not None:
@@ -109,7 +107,7 @@ class RequestEncodingMixin(object):
         """
         if (not files):
             raise ValueError("Files must be provided.")
-        elif isinstance(data, basestring):
+        elif isinstance(data, str):
             raise ValueError("Data must not be a string.")
 
         new_fields = []
@@ -117,7 +115,7 @@ class RequestEncodingMixin(object):
         files = to_key_val_list(files or {})
 
         for field, val in fields:
-            if isinstance(val, basestring) or not hasattr(val, '__iter__'):
+            if isinstance(val, str) or not hasattr(val, '__iter__'):
                 val = [val]
             for v in val:
                 if v is not None:
@@ -158,17 +156,17 @@ class RequestEncodingMixin(object):
         return body, content_type
 
 
-class RequestHooksMixin(object):
+class RequestHooksMixin:
     def register_hook(self, event, hook):
         """Properly register a hook."""
 
         if event not in self.hooks:
             raise ValueError('Unsupported event specified, with event name "%s"' % (event))
 
-        if isinstance(hook, collections.Callable):
+        if isinstance(hook, collections.abc.Callable):
             self.hooks[event].append(hook)
         elif hasattr(hook, '__iter__'):
-            self.hooks[event].extend(h for h in hook if isinstance(h, collections.Callable))
+            self.hooks[event].extend(h for h in hook if isinstance(h, collections.abc.Callable))
 
     def deregister_hook(self, event, hook):
         """Deregister a previously registered hook.
@@ -331,7 +329,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
         if isinstance(url, bytes):
             url = url.decode('utf8')
         else:
-            url = unicode(url) if is_py2 else str(url)
+            url = str(url) if is_py2 else str(url)
 
         # Don't do any URL preparation for non-HTTP schemes like `mailto`,
         # `data` etc to work around exceptions from `url_parse`, which
@@ -391,7 +389,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
         enc_params = self._encode_params(params)
         if enc_params:
             if query:
-                query = '%s&%s' % (query, enc_params)
+                query = '{}&{}'.format(query, enc_params)
             else:
                 query = enc_params
 
@@ -423,7 +421,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
 
         is_stream = all([
             hasattr(data, '__iter__'),
-            not isinstance(data, (basestring, list, tuple, dict))
+            not isinstance(data, (str, list, tuple, dict))
         ])
 
         try:
@@ -448,7 +446,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
             else:
                 if data:
                     body = self._encode_params(data)
-                    if isinstance(data, basestring) or hasattr(data, 'read'):
+                    if isinstance(data, str) or hasattr(data, 'read'):
                         content_type = None
                     else:
                         content_type = 'application/x-www-form-urlencoded'
@@ -525,7 +523,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
             self.register_hook(event, hooks[event])
 
 
-class Response(object):
+class Response:
     """The :class:`Response <Response>` object, which contains a
     server's response to an HTTP request.
     """
@@ -536,7 +534,7 @@ class Response(object):
     ]
 
     def __init__(self):
-        super(Response, self).__init__()
+        super().__init__()
 
         self._content = False
         self._content_consumed = False
@@ -589,10 +587,10 @@ class Response(object):
         if not self._content_consumed:
             self.content
 
-        return dict(
-            (attr, getattr(self, attr, None))
+        return {
+            attr: getattr(self, attr, None)
             for attr in self.__attrs__
-        )
+        }
 
     def __setstate__(self, state):
         for name, value in state.items():
@@ -714,8 +712,7 @@ class Response(object):
             else:
                 pending = None
 
-            for line in lines:
-                yield line
+            yield from lines
 
         if pending is not None:
             yield pending
@@ -734,7 +731,7 @@ class Response(object):
                 if self.status_code == 0:
                     self._content = None
                 else:
-                    self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
+                    self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
 
             except AttributeError:
                 self._content = None
@@ -762,7 +759,7 @@ class Response(object):
         encoding = self.encoding
 
         if not self.content:
-            return str('')
+            return ''
 
         # Fallback to auto-detected encoding.
         if self.encoding is None:
@@ -783,7 +780,7 @@ class Response(object):
         return content
 
     def json(self, **kwargs):
-        """Returns the json-encoded content of a response, if any.
+        r"""Returns the json-encoded content of a response, if any.
 
         :param \*\*kwargs: Optional arguments that ``json.loads`` takes.
         """
@@ -831,10 +828,10 @@ class Response(object):
         http_error_msg = ''
 
         if 400 <= self.status_code < 500:
-            http_error_msg = '%s Client Error: %s for url: %s' % (self.status_code, self.reason, self.url)
+            http_error_msg = '{} Client Error: {} for url: {}'.format(self.status_code, self.reason, self.url)
 
         elif 500 <= self.status_code < 600:
-            http_error_msg = '%s Server Error: %s for url: %s' % (self.status_code, self.reason, self.url)
+            http_error_msg = '{} Server Error: {} for url: {}'.format(self.status_code, self.reason, self.url)
 
         if http_error_msg:
             raise HTTPError(http_error_msg, response=self)
diff --git a/python/requests/requests/packages/__init__.py b/python/requests/requests/packages/__init__.py
index 971c2ad024..cb2525372d 100644
--- a/python/requests/requests/packages/__init__.py
+++ b/python/requests/requests/packages/__init__.py
@@ -20,17 +20,16 @@ https://github.com/kennethreitz/requests/pull/2375 for the corresponding pull
 request.
 '''
 
-from __future__ import absolute_import
 import sys
 
 try:
     from . import urllib3
 except ImportError:
-    import urllib3
+    from . import urllib3
     sys.modules['%s.urllib3' % __name__] = urllib3
 
 try:
     from . import chardet
 except ImportError:
-    import chardet
+    from . import chardet
     sys.modules['%s.chardet' % __name__] = chardet
diff --git a/python/requests/requests/packages/chardet/__init__.py b/python/requests/requests/packages/chardet/__init__.py
index 82c2a48d29..09d2a3991f 100644
--- a/python/requests/requests/packages/chardet/__init__.py
+++ b/python/requests/requests/packages/chardet/__init__.py
@@ -20,7 +20,7 @@ from sys import version_info
 
 
 def detect(aBuf):
-    if ((version_info < (3, 0) and isinstance(aBuf, unicode)) or
+    if ((version_info < (3, 0) and isinstance(aBuf, str)) or
             (version_info >= (3, 0) and not isinstance(aBuf, bytes))):
         raise ValueError('Expected a bytes object, not a unicode object')
 
diff --git a/python/requests/requests/packages/chardet/chardetect.py b/python/requests/requests/packages/chardet/chardetect.py
index ffe892f25d..59549cc9ee 100755
--- a/python/requests/requests/packages/chardet/chardetect.py
+++ b/python/requests/requests/packages/chardet/chardetect.py
@@ -13,11 +13,9 @@ If no paths are provided, it takes its input from stdin.
 
 """
 
-from __future__ import absolute_import, print_function, unicode_literals
 
 import argparse
 import sys
-from io import open
 
 from chardet import __version__
 from chardet.universaldetector import UniversalDetector
@@ -39,10 +37,10 @@ def description_of(lines, name='stdin'):
     u.close()
     result = u.result
     if result['encoding']:
-        return '{0}: {1} with confidence {2}'.format(name, result['encoding'],
+        return '{}: {} with confidence {}'.format(name, result['encoding'],
                                                      result['confidence'])
     else:
-        return '{0}: no result'.format(name)
+        return '{}: no result'.format(name)
 
 
 def main(argv=None):
@@ -64,7 +62,7 @@ def main(argv=None):
                         type=argparse.FileType('rb'), nargs='*',
                         default=[sys.stdin])
     parser.add_argument('--version', action='version',
-                        version='%(prog)s {0}'.format(__version__))
+                        version='%(prog)s {}'.format(__version__))
     args = parser.parse_args(argv)
 
     for f in args.input:
diff --git a/python/requests/requests/packages/chardet/compat.py b/python/requests/requests/packages/chardet/compat.py
index d9e30addf9..6c6ad50416 100644
--- a/python/requests/requests/packages/chardet/compat.py
+++ b/python/requests/requests/packages/chardet/compat.py
@@ -21,10 +21,7 @@
 import sys
 
 
-if sys.version_info < (3, 0):
-    base_str = (str, unicode)
-else:
-    base_str = (bytes, str)
+base_str = (bytes, str)
 
 
 def wrap_ord(a):
diff --git a/python/requests/requests/packages/urllib3/__init__.py b/python/requests/requests/packages/urllib3/__init__.py
index e43991a974..c1123aae8d 100644
--- a/python/requests/requests/packages/urllib3/__init__.py
+++ b/python/requests/requests/packages/urllib3/__init__.py
@@ -2,7 +2,6 @@
 urllib3 - Thread-safe connection pooling and re-using.
 """
 
-from __future__ import absolute_import
 import warnings
 
 from .connectionpool import (
diff --git a/python/requests/requests/packages/urllib3/_collections.py b/python/requests/requests/packages/urllib3/_collections.py
index 67f3ce994d..1bdbb7d48c 100644
--- a/python/requests/requests/packages/urllib3/_collections.py
+++ b/python/requests/requests/packages/urllib3/_collections.py
@@ -1,5 +1,4 @@
-from __future__ import absolute_import
-from collections import Mapping, MutableMapping
+from collections.abc import Mapping, MutableMapping
 try:
     from threading import RLock
 except ImportError:  # Platform-specific: No threads available
@@ -133,7 +132,7 @@ class HTTPHeaderDict(MutableMapping):
     """
 
     def __init__(self, headers=None, **kwargs):
-        super(HTTPHeaderDict, self).__init__()
+        super().__init__()
         self._container = {}
         if headers is not None:
             if isinstance(headers, HTTPHeaderDict):
@@ -162,8 +161,8 @@ class HTTPHeaderDict(MutableMapping):
             return False
         if not isinstance(other, type(self)):
             other = type(self)(other)
-        return (dict((k.lower(), v) for k, v in self.itermerged()) ==
-                dict((k.lower(), v) for k, v in other.itermerged()))
+        return ({k.lower(): v for k, v in self.itermerged()} ==
+                {k.lower(): v for k, v in other.itermerged()})
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -235,11 +234,11 @@ class HTTPHeaderDict(MutableMapping):
         """
         if len(args) > 1:
             raise TypeError("extend() takes at most 1 positional "
-                            "arguments ({0} given)".format(len(args)))
+                            "arguments ({} given)".format(len(args)))
         other = args[0] if len(args) >= 1 else ()
 
         if isinstance(other, HTTPHeaderDict):
-            for key, val in other.iteritems():
+            for key, val in other.items():
                 self.add(key, val)
         elif isinstance(other, Mapping):
             for key in other:
@@ -273,7 +272,7 @@ class HTTPHeaderDict(MutableMapping):
     iget = getlist
 
     def __repr__(self):
-        return "%s(%s)" % (type(self).__name__, dict(self.itermerged()))
+        return "{}({})".format(type(self).__name__, dict(self.itermerged()))
 
     def _copy_from(self, other):
         for key in other:
@@ -302,7 +301,7 @@ class HTTPHeaderDict(MutableMapping):
             yield val[0], ', '.join(val[1:])
 
     def items(self):
-        return list(self.iteritems())
+        return list(self.items())
 
     @classmethod
     def from_httplib(cls, message):  # Python 2
diff --git a/python/requests/requests/packages/urllib3/connection.py b/python/requests/requests/packages/urllib3/connection.py
index 1e4cd41758..4b2de5a4e3 100644
--- a/python/requests/requests/packages/urllib3/connection.py
+++ b/python/requests/requests/packages/urllib3/connection.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import datetime
 import os
 import sys
@@ -11,8 +10,8 @@ try:  # Python 3
     from http.client import HTTPConnection as _HTTPConnection
     from http.client import HTTPException  # noqa: unused in this module
 except ImportError:
-    from httplib import HTTPConnection as _HTTPConnection
-    from httplib import HTTPException  # noqa: unused in this module
+    from six.moves.http_client import HTTPConnection as _HTTPConnection
+    from six.moves.http_client import HTTPException  # noqa: unused in this module
 
 try:  # Compiled with SSL?
     import ssl
@@ -58,12 +57,12 @@ port_by_scheme = {
 RECENT_DATE = datetime.date(2014, 1, 1)
 
 
-class DummyConnection(object):
+class DummyConnection:
     """Used to detect a failed ConnectionCls import."""
     pass
 
 
-class HTTPConnection(_HTTPConnection, object):
+class HTTPConnection(_HTTPConnection):
     """
     Based on httplib.HTTPConnection but provides an extra constructor
     backwards-compatibility layer between older and newer Pythons.
@@ -100,8 +99,7 @@ class HTTPConnection(_HTTPConnection, object):
     is_verified = False
 
     def __init__(self, *args, **kw):
-        if six.PY3:  # Python 3
-            kw.pop('strict', None)
+        kw.pop('strict', None)
 
         # Pre-set source_address in case we have an older Python like 2.6.
         self.source_address = kw.get('source_address')
@@ -237,7 +235,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
         is_time_off = datetime.date.today() < RECENT_DATE
         if is_time_off:
             warnings.warn((
-                'System time is way off (before {0}). This will probably '
+                'System time is way off (before {}). This will probably '
                 'lead to SSL verification errors').format(RECENT_DATE),
                 SystemTimeWarning
             )
@@ -259,7 +257,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
             cert = self.sock.getpeercert()
             if not cert.get('subjectAltName', ()):
                 warnings.warn((
-                    'Certificate for {0} has no `subjectAltName`, falling back to check for a '
+                    'Certificate for {} has no `subjectAltName`, falling back to check for a '
                     '`commonName` for now. This feature is being removed by major browsers and '
                     'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 '
                     'for details.)'.format(hostname)),
diff --git a/python/requests/requests/packages/urllib3/connectionpool.py b/python/requests/requests/packages/urllib3/connectionpool.py
index 995b4167b5..67e755f303 100644
--- a/python/requests/requests/packages/urllib3/connectionpool.py
+++ b/python/requests/requests/packages/urllib3/connectionpool.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import errno
 import logging
 import sys
@@ -10,9 +9,9 @@ import socket
 try:  # Python 3
     from queue import LifoQueue, Empty, Full
 except ImportError:
-    from Queue import LifoQueue, Empty, Full
+    from queue import LifoQueue, Empty, Full
     # Queue is imported for side effects on MS Windows
-    import Queue as _unused_module_Queue  # noqa: unused
+    import six.moves.queue as _unused_module_Queue  # noqa: unused
 
 
 from .exceptions import (
@@ -48,7 +47,7 @@ from .util.timeout import Timeout
 from .util.url import get_host, Url
 
 
-xrange = six.moves.xrange
+xrange = range
 
 log = logging.getLogger(__name__)
 
@@ -56,7 +55,7 @@ _Default = object()
 
 
 # Pool objects
-class ConnectionPool(object):
+class ConnectionPool:
     """
     Base class for all connection pools, such as
     :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
@@ -73,7 +72,7 @@ class ConnectionPool(object):
         self.port = port
 
     def __str__(self):
-        return '%s(host=%r, port=%r)' % (type(self).__name__,
+        return '{}(host={!r}, port={!r})'.format(type(self).__name__,
                                          self.host, self.port)
 
     def __enter__(self):
@@ -92,11 +91,11 @@ class ConnectionPool(object):
 
 
 # This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252
-_blocking_errnos = set([errno.EAGAIN, errno.EWOULDBLOCK])
+_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK}
 
 
 class HTTPConnectionPool(ConnectionPool, RequestMethods):
-    """
+    r"""
     Thread-safe connection pool for one host.
 
     :param host:
@@ -184,7 +183,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
         self.proxy_headers = _proxy_headers or {}
 
         # Fill the queue up so that doing get() on it will block properly
-        for _ in xrange(maxsize):
+        for _ in range(maxsize):
             self.pool.put(None)
 
         # These are mostly for testing and debugging purposes.
@@ -382,7 +381,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
 
         # AppEngine doesn't have a version attr.
         http_version = getattr(conn, '_http_vsn_str', 'HTTP/?')
-        log.debug("\"%s %s %s\" %s %s" % (method, url, http_version,
+        log.debug("\"{} {} {}\" {} {}".format(method, url, http_version,
                                           httplib_response.status,
                                           httplib_response.length))
 
@@ -436,7 +435,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
     def urlopen(self, method, url, body=None, headers=None, retries=None,
                 redirect=True, assert_same_host=True, timeout=_Default,
                 pool_timeout=None, release_conn=None, **response_kw):
-        """
+        r"""
         Get a connection from the pool and perform an HTTP request. This is the
         lowest level call for making a request, so you'll need to specify all
         the raw details.
@@ -644,7 +643,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
                     raise
                 return response
 
-            log.info("Redirecting %s -> %s" % (url, redirect_location))
+            log.info("Redirecting {} -> {}".format(url, redirect_location))
             return self.urlopen(
                 method, redirect_location, body, headers,
                 retries=retries, redirect=redirect,
@@ -777,7 +776,7 @@ class HTTPSConnectionPool(HTTPConnectionPool):
         """
         Called right before a request is made, after the socket is created.
         """
-        super(HTTPSConnectionPool, self)._validate_conn(conn)
+        super()._validate_conn(conn)
 
         # Force connect early to allow us to validate the connection.
         if not getattr(conn, 'sock', None):  # AppEngine might not have  `.sock`
@@ -792,7 +791,7 @@ class HTTPSConnectionPool(HTTPConnectionPool):
 
 
 def connection_from_url(url, **kw):
-    """
+    r"""
     Given a url, return an :class:`.ConnectionPool` instance of its host.
 
     This is a shortcut for not having to parse out the scheme, host, and port
diff --git a/python/requests/requests/packages/urllib3/contrib/appengine.py b/python/requests/requests/packages/urllib3/contrib/appengine.py
index 884cdb220d..06390643f0 100644
--- a/python/requests/requests/packages/urllib3/contrib/appengine.py
+++ b/python/requests/requests/packages/urllib3/contrib/appengine.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import logging
 import os
 import warnings
diff --git a/python/requests/requests/packages/urllib3/contrib/ntlmpool.py b/python/requests/requests/packages/urllib3/contrib/ntlmpool.py
index c136a238db..4ebd26722c 100644
--- a/python/requests/requests/packages/urllib3/contrib/ntlmpool.py
+++ b/python/requests/requests/packages/urllib3/contrib/ntlmpool.py
@@ -3,12 +3,11 @@ NTLM authenticating pool, contributed by erikcederstran
 
 Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10
 """
-from __future__ import absolute_import
 
 try:
     from http.client import HTTPSConnection
 except ImportError:
-    from httplib import HTTPSConnection
+    from six.moves.http_client import HTTPSConnection
 from logging import getLogger
 from ntlm import ntlm
 
@@ -31,7 +30,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
         user is the Windows user, probably in the DOMAIN\\username format.
         pw is the password for the user.
         """
-        super(NTLMConnectionPool, self).__init__(*args, **kwargs)
+        super().__init__(*args, **kwargs)
         self.authurl = authurl
         self.rawuser = user
         user_parts = user.split('\\', 1)
@@ -60,7 +59,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
         conn.request('GET', self.authurl, None, headers)
         res = conn.getresponse()
         reshdr = dict(res.getheaders())
-        log.debug('Response status: %s %s' % (res.status, res.reason))
+        log.debug('Response status: {} {}'.format(res.status, res.reason))
         log.debug('Response headers: %s' % reshdr)
         log.debug('Response data: %s [...]' % res.read(100))
 
@@ -90,7 +89,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
         log.debug('Request headers: %s' % headers)
         conn.request('GET', self.authurl, None, headers)
         res = conn.getresponse()
-        log.debug('Response status: %s %s' % (res.status, res.reason))
+        log.debug('Response status: {} {}'.format(res.status, res.reason))
         log.debug('Response headers: %s' % dict(res.getheaders()))
         log.debug('Response data: %s [...]' % res.read()[:100])
         if res.status != 200:
@@ -109,7 +108,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
         if headers is None:
             headers = {}
         headers['Connection'] = 'Keep-Alive'
-        return super(NTLMConnectionPool, self).urlopen(method, url, body,
+        return super().urlopen(method, url, body,
                                                        headers, retries,
                                                        redirect,
                                                        assert_same_host)
diff --git a/python/requests/requests/packages/urllib3/contrib/pyopenssl.py b/python/requests/requests/packages/urllib3/contrib/pyopenssl.py
index 5996153afe..ba3d83814b 100644
--- a/python/requests/requests/packages/urllib3/contrib/pyopenssl.py
+++ b/python/requests/requests/packages/urllib3/contrib/pyopenssl.py
@@ -43,7 +43,6 @@ Module Variables
 .. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)
 
 '''
-from __future__ import absolute_import
 
 try:
     from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT
@@ -155,7 +154,7 @@ def get_subj_alt_name(peer_cert):
     return dns_name
 
 
-class WrappedSocket(object):
+class WrappedSocket:
     '''API-compatibility wrapper for Python OpenSSL's Connection-class.
 
     Note: _makefile_refs, _drop() and _reuse() are needed for the garbage
diff --git a/python/requests/requests/packages/urllib3/exceptions.py b/python/requests/requests/packages/urllib3/exceptions.py
index 8e07eb6198..eeb9927f1d 100644
--- a/python/requests/requests/packages/urllib3/exceptions.py
+++ b/python/requests/requests/packages/urllib3/exceptions.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 # Base Exceptions
 
 
@@ -16,7 +15,7 @@ class PoolError(HTTPError):
     "Base exception for errors caused within a pool."
     def __init__(self, pool, message):
         self.pool = pool
-        HTTPError.__init__(self, "%s: %s" % (pool, message))
+        HTTPError.__init__(self, "{}: {}".format(pool, message))
 
     def __reduce__(self):
         # For pickling purposes.
@@ -73,7 +72,7 @@ class MaxRetryError(RequestError):
     def __init__(self, pool, url, reason=None):
         self.reason = reason
 
-        message = "Max retries exceeded with url: %s (Caused by %r)" % (
+        message = "Max retries exceeded with url: {} (Caused by {!r})".format(
             url, reason)
 
         RequestError.__init__(self, pool, url, message)
@@ -191,11 +190,11 @@ class ProxySchemeUnknown(AssertionError, ValueError):
 
     def __init__(self, scheme):
         message = "Not supported proxy scheme %s" % scheme
-        super(ProxySchemeUnknown, self).__init__(message)
+        super().__init__(message)
 
 
 class HeaderParsingError(HTTPError):
     "Raised by assert_header_parsing, but we convert it to a log.warning statement."
     def __init__(self, defects, unparsed_data):
-        message = '%s, unparsed data: %r' % (defects or 'Unknown', unparsed_data)
-        super(HeaderParsingError, self).__init__(message)
+        message = '{}, unparsed data: {!r}'.format(defects or 'Unknown', unparsed_data)
+        super().__init__(message)
diff --git a/python/requests/requests/packages/urllib3/fields.py b/python/requests/requests/packages/urllib3/fields.py
index c7d48113bd..b7d7cd89aa 100644
--- a/python/requests/requests/packages/urllib3/fields.py
+++ b/python/requests/requests/packages/urllib3/fields.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import email.utils
 import mimetypes
 
@@ -33,21 +32,21 @@ def format_header_param(name, value):
         The value of the parameter, provided as a unicode string.
     """
     if not any(ch in value for ch in '"\\\r\n'):
-        result = '%s="%s"' % (name, value)
+        result = '{}="{}"'.format(name, value)
         try:
             result.encode('ascii')
         except UnicodeEncodeError:
             pass
         else:
             return result
-    if not six.PY3:  # Python 2:
+    if not True:  # Python 2:
         value = value.encode('utf-8')
     value = email.utils.encode_rfc2231(value, 'utf-8')
-    value = '%s*=%s' % (name, value)
+    value = '{}*={}'.format(name, value)
     return value
 
 
-class RequestField(object):
+class RequestField:
     """
     A data container for request body parameters.
 
@@ -127,7 +126,7 @@ class RequestField(object):
         parts = []
         iterable = header_parts
         if isinstance(header_parts, dict):
-            iterable = header_parts.items()
+            iterable = list(header_parts.items())
 
         for name, value in iterable:
             if value:
@@ -144,12 +143,12 @@ class RequestField(object):
         sort_keys = ['Content-Disposition', 'Content-Type', 'Content-Location']
         for sort_key in sort_keys:
             if self.headers.get(sort_key, False):
-                lines.append('%s: %s' % (sort_key, self.headers[sort_key]))
+                lines.append('{}: {}'.format(sort_key, self.headers[sort_key]))
 
         for header_name, header_value in self.headers.items():
             if header_name not in sort_keys:
                 if header_value:
-                    lines.append('%s: %s' % (header_name, header_value))
+                    lines.append('{}: {}'.format(header_name, header_value))
 
         lines.append('\r\n')
         return '\r\n'.join(lines)
diff --git a/python/requests/requests/packages/urllib3/filepost.py b/python/requests/requests/packages/urllib3/filepost.py
index 97a2843ca4..b7cf71454a 100644
--- a/python/requests/requests/packages/urllib3/filepost.py
+++ b/python/requests/requests/packages/urllib3/filepost.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import codecs
 
 from uuid import uuid4
@@ -27,7 +26,7 @@ def iter_field_objects(fields):
 
     """
     if isinstance(fields, dict):
-        i = six.iteritems(fields)
+        i = list(fields.items())
     else:
         i = iter(fields)
 
@@ -51,7 +50,7 @@ def iter_fields(fields):
     Supports list of (k, v) tuples and dicts.
     """
     if isinstance(fields, dict):
-        return ((k, v) for k, v in six.iteritems(fields))
+        return ((k, v) for k, v in fields.items())
 
     return ((k, v) for k, v in fields)
 
@@ -80,7 +79,7 @@ def encode_multipart_formdata(fields, boundary=None):
         if isinstance(data, int):
             data = str(data)  # Backwards compatibility
 
-        if isinstance(data, six.text_type):
+        if isinstance(data, str):
             writer(body).write(data)
         else:
             body.write(data)
diff --git a/python/requests/requests/packages/urllib3/packages/__init__.py b/python/requests/requests/packages/urllib3/packages/__init__.py
index 170e974c15..2fdf1ea04d 100644
--- a/python/requests/requests/packages/urllib3/packages/__init__.py
+++ b/python/requests/requests/packages/urllib3/packages/__init__.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import
-
 from . import ssl_match_hostname
 
 __all__ = ('ssl_match_hostname', )
diff --git a/python/requests/requests/packages/urllib3/packages/ordered_dict.py b/python/requests/requests/packages/urllib3/packages/ordered_dict.py
index 4479363cc4..816f97c53e 100644
--- a/python/requests/requests/packages/urllib3/packages/ordered_dict.py
+++ b/python/requests/requests/packages/urllib3/packages/ordered_dict.py
@@ -3,9 +3,9 @@
 # Copyright 2009 Raymond Hettinger, released under the MIT License.
 # http://code.activestate.com/recipes/576693/
 try:
-    from thread import get_ident as _get_ident
+    from _thread import get_ident as _get_ident
 except ImportError:
-    from dummy_thread import get_ident as _get_ident
+    from six.moves._dummy_thread import get_ident as _get_ident
 
 try:
     from _abcoll import KeysView, ValuesView, ItemsView
@@ -79,7 +79,7 @@ class OrderedDict(dict):
     def clear(self):
         'od.clear() -> None.  Remove all items from od.'
         try:
-            for node in self.__map.itervalues():
+            for node in self.__map.values():
                 del node[:]
             root = self.__root
             root[:] = [root, root, None]
@@ -202,8 +202,8 @@ class OrderedDict(dict):
         _repr_running[call_key] = 1
         try:
             if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
+                return '{}()'.format(self.__class__.__name__)
+            return '{}({!r})'.format(self.__class__.__name__, list(self.items()))
         finally:
             del _repr_running[call_key]
 
@@ -238,7 +238,7 @@ class OrderedDict(dict):
 
         '''
         if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
+            return len(self)==len(other) and list(self.items()) == list(other.items())
         return dict.__eq__(self, other)
 
     def __ne__(self, other):
diff --git a/python/requests/requests/packages/urllib3/packages/six.py b/python/requests/requests/packages/urllib3/packages/six.py
index 27d80112bf..6ad7ea98a1 100644
--- a/python/requests/requests/packages/urllib3/packages/six.py
+++ b/python/requests/requests/packages/urllib3/packages/six.py
@@ -22,6 +22,7 @@
 import operator
 import sys
 import types
+from . import six
 
 __author__ = "Benjamin Peterson <benjamin@python.org>"
 __version__ = "1.2.0"  # Revision 41c74fef2ded
@@ -39,10 +40,10 @@ if PY3:
 
     MAXSIZE = sys.maxsize
 else:
-    string_types = basestring,
-    integer_types = (int, long)
-    class_types = (type, types.ClassType)
-    text_type = unicode
+    string_types = str,
+    integer_types = int
+    class_types = (type, type)
+    text_type = str
     binary_type = str
 
     if sys.platform.startswith("java"):
@@ -50,7 +51,7 @@ else:
         MAXSIZE = int((1 << 31) - 1)
     else:
         # It's possible to have sizeof(long) != sizeof(Py_ssize_t).
-        class X(object):
+        class X:
             def __len__(self):
                 return 1 << 31
         try:
@@ -75,7 +76,7 @@ def _import_module(name):
     return sys.modules[name]
 
 
-class _LazyDescr(object):
+class _LazyDescr:
 
     def __init__(self, name):
         self.name = name
@@ -91,7 +92,7 @@ class _LazyDescr(object):
 class MovedModule(_LazyDescr):
 
     def __init__(self, name, old, new=None):
-        super(MovedModule, self).__init__(name)
+        super().__init__(name)
         if PY3:
             if new is None:
                 new = name
@@ -106,7 +107,7 @@ class MovedModule(_LazyDescr):
 class MovedAttribute(_LazyDescr):
 
     def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
-        super(MovedAttribute, self).__init__(name)
+        super().__init__(name)
         if PY3:
             if new_mod is None:
                 new_mod = name
@@ -199,7 +200,7 @@ def remove_move(name):
         try:
             del moves.__dict__[name]
         except KeyError:
-            raise AttributeError("no such move, %r" % (name,))
+            raise AttributeError("no such move, {!r}".format(name))
 
 
 if PY3:
@@ -228,7 +229,7 @@ try:
     advance_iterator = next
 except NameError:
     def advance_iterator(it):
-        return it.next()
+        return next(it)
 next = advance_iterator
 
 
@@ -242,9 +243,9 @@ if PY3:
         return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
 else:
     def get_unbound_function(unbound):
-        return unbound.im_func
+        return unbound.__func__
 
-    class Iterator(object):
+    class Iterator:
 
         def next(self):
             return type(self).__next__(self)
@@ -291,7 +292,7 @@ else:
     def b(s):
         return s
     def u(s):
-        return unicode(s, "unicode_escape")
+        return str(s, "unicode_escape")
     int2byte = chr
     import StringIO
     StringIO = BytesIO = StringIO.StringIO
@@ -328,7 +329,7 @@ else:
 
 
     exec_("""def reraise(tp, value, tb=None):
-    raise tp, value, tb
+    raise tp(value, tb)
 """)
 
 
@@ -338,19 +339,19 @@ else:
         if fp is None:
             return
         def write(data):
-            if not isinstance(data, basestring):
+            if not isinstance(data, str):
                 data = str(data)
             fp.write(data)
         want_unicode = False
         sep = kwargs.pop("sep", None)
         if sep is not None:
-            if isinstance(sep, unicode):
+            if isinstance(sep, str):
                 want_unicode = True
             elif not isinstance(sep, str):
                 raise TypeError("sep must be None or a string")
         end = kwargs.pop("end", None)
         if end is not None:
-            if isinstance(end, unicode):
+            if isinstance(end, str):
                 want_unicode = True
             elif not isinstance(end, str):
                 raise TypeError("end must be None or a string")
@@ -358,12 +359,12 @@ else:
             raise TypeError("invalid keyword arguments to print()")
         if not want_unicode:
             for arg in args:
-                if isinstance(arg, unicode):
+                if isinstance(arg, str):
                     want_unicode = True
                     break
         if want_unicode:
-            newline = unicode("\n")
-            space = unicode(" ")
+            newline = str("\n")
+            space = str(" ")
         else:
             newline = "\n"
             space = " "
diff --git a/python/requests/requests/packages/urllib3/poolmanager.py b/python/requests/requests/packages/urllib3/poolmanager.py
index f13e673d1f..8e1be95559 100644
--- a/python/requests/requests/packages/urllib3/poolmanager.py
+++ b/python/requests/requests/packages/urllib3/poolmanager.py
@@ -1,10 +1,9 @@
-from __future__ import absolute_import
 import logging
 
 try:  # Python 3
     from urllib.parse import urljoin
 except ImportError:
-    from urlparse import urljoin
+    from urllib.parse import urljoin
 
 from ._collections import RecentlyUsedContainer
 from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool
@@ -30,7 +29,7 @@ SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs',
 
 
 class PoolManager(RequestMethods):
-    """
+    r"""
     Allows for arbitrary requests while transparently keeping track of
     necessary connection pools for you.
 
@@ -186,7 +185,7 @@ class PoolManager(RequestMethods):
         kw['retries'] = retries
         kw['redirect'] = redirect
 
-        log.info("Redirecting %s -> %s" % (url, redirect_location))
+        log.info("Redirecting {} -> {}".format(url, redirect_location))
         return self.urlopen(method, redirect_location, **kw)
 
 
@@ -237,15 +236,15 @@ class ProxyManager(PoolManager):
         connection_pool_kw['_proxy'] = self.proxy
         connection_pool_kw['_proxy_headers'] = self.proxy_headers
 
-        super(ProxyManager, self).__init__(
+        super().__init__(
             num_pools, headers, **connection_pool_kw)
 
     def connection_from_host(self, host, port=None, scheme='http'):
         if scheme == "https":
-            return super(ProxyManager, self).connection_from_host(
+            return super().connection_from_host(
                 host, port, scheme)
 
-        return super(ProxyManager, self).connection_from_host(
+        return super().connection_from_host(
             self.proxy.host, self.proxy.port, self.proxy.scheme)
 
     def _set_proxy_headers(self, url, headers=None):
@@ -274,7 +273,7 @@ class ProxyManager(PoolManager):
             headers = kw.get('headers', self.headers)
             kw['headers'] = self._set_proxy_headers(url, headers)
 
-        return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw)
+        return super().urlopen(method, url, redirect=redirect, **kw)
 
 
 def proxy_from_url(url, **kw):
diff --git a/python/requests/requests/packages/urllib3/request.py b/python/requests/requests/packages/urllib3/request.py
index d5aa62d887..84e118f18a 100644
--- a/python/requests/requests/packages/urllib3/request.py
+++ b/python/requests/requests/packages/urllib3/request.py
@@ -1,8 +1,7 @@
-from __future__ import absolute_import
 try:
     from urllib.parse import urlencode
 except ImportError:
-    from urllib import urlencode
+    from urllib.parse import urlencode
 
 from .filepost import encode_multipart_formdata
 
@@ -10,7 +9,7 @@ from .filepost import encode_multipart_formdata
 __all__ = ['RequestMethods']
 
 
-class RequestMethods(object):
+class RequestMethods:
     """
     Convenience mixin for classes who implement a :meth:`urlopen` method, such
     as :class:`~urllib3.connectionpool.HTTPConnectionPool` and
@@ -39,7 +38,7 @@ class RequestMethods(object):
         explicitly.
     """
 
-    _encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS'])
+    _encode_url_methods = {'DELETE', 'GET', 'HEAD', 'OPTIONS'}
 
     def __init__(self, headers=None):
         self.headers = headers or {}
diff --git a/python/requests/requests/packages/urllib3/response.py b/python/requests/requests/packages/urllib3/response.py
index 8f2a1b5c29..83a6ff539e 100644
--- a/python/requests/requests/packages/urllib3/response.py
+++ b/python/requests/requests/packages/urllib3/response.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 from contextlib import contextmanager
 import zlib
 import io
@@ -9,13 +8,13 @@ from ._collections import HTTPHeaderDict
 from .exceptions import (
     ProtocolError, DecodeError, ReadTimeoutError, ResponseNotChunked
 )
-from .packages.six import string_types as basestring, binary_type, PY3
+from .packages.six import string_types as str, binary_type, PY3
 from .packages.six.moves import http_client as httplib
 from .connection import HTTPException, BaseSSLError
 from .util.response import is_fp_closed, is_response_to_head
 
 
-class DeflateDecoder(object):
+class DeflateDecoder:
 
     def __init__(self):
         self._first_try = True
@@ -44,7 +43,7 @@ class DeflateDecoder(object):
                 self._data = None
 
 
-class GzipDecoder(object):
+class GzipDecoder:
 
     def __init__(self):
         self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
@@ -114,7 +113,7 @@ class HTTPResponse(io.IOBase):
         self._original_response = original_response
         self._fp_bytes_read = 0
 
-        if body and isinstance(body, (basestring, binary_type)):
+        if body and isinstance(body, (str, binary_type)):
             self._body = body
 
         self._pool = pool
@@ -190,7 +189,7 @@ class HTTPResponse(io.IOBase):
         try:
             if decode_content and self._decoder:
                 data = self._decoder.decompress(data)
-        except (IOError, zlib.error) as e:
+        except (OSError, zlib.error) as e:
             content_encoding = self.headers.get('content-encoding', '').lower()
             raise DecodeError(
                 "Received response with content-encoding: %s, but "
@@ -337,8 +336,7 @@ class HTTPResponse(io.IOBase):
             'content-encoding' header.
         """
         if self.chunked:
-            for line in self.read_chunked(amt, decode_content=decode_content):
-                yield line
+            yield from self.read_chunked(amt, decode_content=decode_content)
         else:
             while not is_fp_closed(self._fp):
                 data = self.read(amt=amt, decode_content=decode_content)
@@ -359,7 +357,7 @@ class HTTPResponse(io.IOBase):
 
         if not isinstance(headers, HTTPHeaderDict):
             if PY3:  # Python 3
-                headers = HTTPHeaderDict(headers.items())
+                headers = HTTPHeaderDict(list(headers.items()))
             else:  # Python 2
                 headers = HTTPHeaderDict.from_httplib(headers)
 
@@ -400,11 +398,11 @@ class HTTPResponse(io.IOBase):
 
     def fileno(self):
         if self._fp is None:
-            raise IOError("HTTPResponse has no file to get a fileno from")
+            raise OSError("HTTPResponse has no file to get a fileno from")
         elif hasattr(self._fp, "fileno"):
             return self._fp.fileno()
         else:
-            raise IOError("The file-like object this HTTPResponse is wrapped "
+            raise OSError("The file-like object this HTTPResponse is wrapped "
                           "around has no file descriptor")
 
     def flush(self):
diff --git a/python/requests/requests/packages/urllib3/util/__init__.py b/python/requests/requests/packages/urllib3/util/__init__.py
index c6c6243cf1..ccdf06977a 100644
--- a/python/requests/requests/packages/urllib3/util/__init__.py
+++ b/python/requests/requests/packages/urllib3/util/__init__.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 # For backwards compatibility, provide imports that used to be here.
 from .connection import is_connection_dropped
 from .request import make_headers
diff --git a/python/requests/requests/packages/urllib3/util/connection.py b/python/requests/requests/packages/urllib3/util/connection.py
index 01a4812f21..04a04651a4 100644
--- a/python/requests/requests/packages/urllib3/util/connection.py
+++ b/python/requests/requests/packages/urllib3/util/connection.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import socket
 try:
     from select import poll, POLLIN
@@ -32,7 +31,7 @@ def is_connection_dropped(conn):  # Platform-specific
 
         try:
             return select([sock], [], [], 0.0)[0]
-        except socket.error:
+        except OSError:
             return True
 
     # This version is better on platforms that support it.
@@ -81,7 +80,7 @@ def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
             sock.connect(sa)
             return sock
 
-        except socket.error as e:
+        except OSError as e:
             err = e
             if sock is not None:
                 sock.close()
@@ -90,7 +89,7 @@ def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
     if err is not None:
         raise err
 
-    raise socket.error("getaddrinfo returns an empty list")
+    raise OSError("getaddrinfo returns an empty list")
 
 
 def _set_socket_options(sock, options):
diff --git a/python/requests/requests/packages/urllib3/util/request.py b/python/requests/requests/packages/urllib3/util/request.py
index 73779315f4..bc64f6b1fb 100644
--- a/python/requests/requests/packages/urllib3/util/request.py
+++ b/python/requests/requests/packages/urllib3/util/request.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 from base64 import b64encode
 
 from ..packages.six import b
diff --git a/python/requests/requests/packages/urllib3/util/response.py b/python/requests/requests/packages/urllib3/util/response.py
index bc7232720d..2c1de154a4 100644
--- a/python/requests/requests/packages/urllib3/util/response.py
+++ b/python/requests/requests/packages/urllib3/util/response.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 from ..packages.six.moves import http_client as httplib
 
 from ..exceptions import HeaderParsingError
@@ -45,7 +44,7 @@ def assert_header_parsing(headers):
     # This will fail silently if we pass in the wrong kind of parameter.
     # To make debugging easier add an explicit check.
     if not isinstance(headers, httplib.HTTPMessage):
-        raise TypeError('expected httplib.Message, got {0}.'.format(
+        raise TypeError('expected httplib.Message, got {}.'.format(
             type(headers)))
 
     defects = getattr(headers, 'defects', None)
diff --git a/python/requests/requests/packages/urllib3/util/retry.py b/python/requests/requests/packages/urllib3/util/retry.py
index 03a01249dd..732a138e42 100644
--- a/python/requests/requests/packages/urllib3/util/retry.py
+++ b/python/requests/requests/packages/urllib3/util/retry.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import time
 import logging
 
@@ -15,7 +14,7 @@ from ..packages import six
 log = logging.getLogger(__name__)
 
 
-class Retry(object):
+class Retry:
     """ Retry configuration.
 
     Each retry attempt will create a new Retry object with updated values, so
@@ -153,7 +152,7 @@ class Retry(object):
 
         redirect = bool(redirect) and None
         new_retries = cls(retries, redirect=redirect)
-        log.debug("Converted retries value: %r -> %r" % (retries, new_retries))
+        log.debug("Converted retries value: {!r} -> {!r}".format(retries, new_retries))
         return new_retries
 
     def get_backoff_time(self):
@@ -201,7 +200,7 @@ class Retry(object):
     def is_exhausted(self):
         """ Are we out of retries? """
         retry_counts = (self.total, self.connect, self.read, self.redirect)
-        retry_counts = list(filter(None, retry_counts))
+        retry_counts = list([_f for _f in retry_counts if _f])
         if not retry_counts:
             return False
 
@@ -272,7 +271,7 @@ class Retry(object):
         if new_retry.is_exhausted():
             raise MaxRetryError(_pool, url, error or ResponseError(cause))
 
-        log.debug("Incremented Retry for (url='%s'): %r" % (url, new_retry))
+        log.debug("Incremented Retry for (url='{}'): {!r}".format(url, new_retry))
 
         return new_retry
 
diff --git a/python/requests/requests/packages/urllib3/util/ssl_.py b/python/requests/requests/packages/urllib3/util/ssl_.py
index 67f83441e2..e29dff4f3e 100644
--- a/python/requests/requests/packages/urllib3/util/ssl_.py
+++ b/python/requests/requests/packages/urllib3/util/ssl_.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 import errno
 import warnings
 import hmac
@@ -76,7 +75,7 @@ try:
 except ImportError:
     import sys
 
-    class SSLContext(object):  # Platform-specific: Python 2 & 3.1
+    class SSLContext:  # Platform-specific: Python 2 & 3.1
         supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or
                                 (3, 2) <= sys.version_info)
 
@@ -147,7 +146,7 @@ def assert_fingerprint(cert, fingerprint):
     hashfunc = HASHFUNC_MAP.get(digest_length)
     if not hashfunc:
         raise SSLError(
-            'Fingerprint of invalid length: {0}'.format(fingerprint))
+            'Fingerprint of invalid length: {}'.format(fingerprint))
 
     # We need encode() here for py32; works on py2 and p33.
     fingerprint_bytes = unhexlify(fingerprint.encode())
@@ -155,7 +154,7 @@ def assert_fingerprint(cert, fingerprint):
     cert_digest = hashfunc(cert).digest()
 
     if not _const_compare_digest(cert_digest, fingerprint_bytes):
-        raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".'
+        raise SSLError('Fingerprints did not match. Expected "{}", got "{}".'
                        .format(fingerprint, hexlify(cert_digest)))
 
 
@@ -290,7 +289,7 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
     if ca_certs or ca_cert_dir:
         try:
             context.load_verify_locations(ca_certs, ca_cert_dir)
-        except IOError as e:  # Platform-specific: Python 2.6, 2.7, 3.2
+        except OSError as e:  # Platform-specific: Python 2.6, 2.7, 3.2
             raise SSLError(e)
         # Py33 raises FileNotFoundError which subclasses OSError
         # These are not equivalent unless we check the errno attribute
diff --git a/python/requests/requests/packages/urllib3/util/timeout.py b/python/requests/requests/packages/urllib3/util/timeout.py
index ff62f4764d..bc0b296fac 100644
--- a/python/requests/requests/packages/urllib3/util/timeout.py
+++ b/python/requests/requests/packages/urllib3/util/timeout.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 # The default socket timeout, used by httplib to indicate that no timeout was
 # specified by the user
 from socket import _GLOBAL_DEFAULT_TIMEOUT
@@ -18,7 +17,7 @@ def current_time():
     return time.time()
 
 
-class Timeout(object):
+class Timeout:
     """ Timeout configuration.
 
     Timeouts can be defined as a default for a pool::
@@ -100,7 +99,7 @@ class Timeout(object):
         self._start_connect = None
 
     def __str__(self):
-        return '%s(connect=%r, read=%r, total=%r)' % (
+        return '{}(connect={!r}, read={!r}, total={!r})'.format(
             type(self).__name__, self._connect, self._read, self.total)
 
     @classmethod
diff --git a/python/requests/requests/packages/urllib3/util/url.py b/python/requests/requests/packages/urllib3/util/url.py
index e996204a07..07c77f1a21 100644
--- a/python/requests/requests/packages/urllib3/util/url.py
+++ b/python/requests/requests/packages/urllib3/util/url.py
@@ -1,4 +1,3 @@
-from __future__ import absolute_import
 from collections import namedtuple
 
 from ..exceptions import LocationParseError
@@ -18,7 +17,7 @@ class Url(namedtuple('Url', url_attrs)):
                 query=None, fragment=None):
         if path and not path.startswith('/'):
             path = '/' + path
-        return super(Url, cls).__new__(cls, scheme, auth, host, port, path,
+        return super().__new__(cls, scheme, auth, host, port, path,
                                        query, fragment)
 
     @property
diff --git a/python/requests/requests/sessions.py b/python/requests/requests/sessions.py
index 9eaa36ae43..aaaa8c9def 100644
--- a/python/requests/requests/sessions.py
+++ b/python/requests/requests/sessions.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.session
 ~~~~~~~~~~~~~~~~
@@ -9,7 +7,7 @@ requests (cookies, auth, proxies).
 
 """
 import os
-from collections import Mapping
+from collections.abc import Mapping
 from datetime import datetime
 
 from .auth import _basic_auth_str
@@ -87,7 +85,7 @@ def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
     return merge_setting(request_hooks, session_hooks, dict_class)
 
 
-class SessionRedirectMixin(object):
+class SessionRedirectMixin:
     def resolve_redirects(self, resp, req, stream=False, timeout=None,
                           verify=True, cert=None, proxies=None, **adapter_kwargs):
         """Receives a Response. Returns a generator of Responses."""
@@ -121,7 +119,7 @@ class SessionRedirectMixin(object):
             # Handle redirection without scheme (see: RFC 1808 Section 4)
             if url.startswith('//'):
                 parsed_rurl = urlparse(resp.url)
-                url = '%s:%s' % (parsed_rurl.scheme, url)
+                url = '{}:{}'.format(parsed_rurl.scheme, url)
 
             # The scheme should be lower case...
             parsed = urlparse(url)
@@ -470,7 +468,7 @@ class Session(SessionRedirectMixin):
         return resp
 
     def get(self, url, **kwargs):
-        """Sends a GET request. Returns :class:`Response` object.
+        r"""Sends a GET request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -480,7 +478,7 @@ class Session(SessionRedirectMixin):
         return self.request('GET', url, **kwargs)
 
     def options(self, url, **kwargs):
-        """Sends a OPTIONS request. Returns :class:`Response` object.
+        r"""Sends a OPTIONS request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -490,7 +488,7 @@ class Session(SessionRedirectMixin):
         return self.request('OPTIONS', url, **kwargs)
 
     def head(self, url, **kwargs):
-        """Sends a HEAD request. Returns :class:`Response` object.
+        r"""Sends a HEAD request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -500,7 +498,7 @@ class Session(SessionRedirectMixin):
         return self.request('HEAD', url, **kwargs)
 
     def post(self, url, data=None, json=None, **kwargs):
-        """Sends a POST request. Returns :class:`Response` object.
+        r"""Sends a POST request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -511,7 +509,7 @@ class Session(SessionRedirectMixin):
         return self.request('POST', url, data=data, json=json, **kwargs)
 
     def put(self, url, data=None, **kwargs):
-        """Sends a PUT request. Returns :class:`Response` object.
+        r"""Sends a PUT request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -521,7 +519,7 @@ class Session(SessionRedirectMixin):
         return self.request('PUT', url, data=data, **kwargs)
 
     def patch(self, url, data=None, **kwargs):
-        """Sends a PATCH request. Returns :class:`Response` object.
+        r"""Sends a PATCH request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
@@ -531,7 +529,7 @@ class Session(SessionRedirectMixin):
         return self.request('PATCH', url,  data=data, **kwargs)
 
     def delete(self, url, **kwargs):
-        """Sends a DELETE request. Returns :class:`Response` object.
+        r"""Sends a DELETE request. Returns :class:`Response` object.
 
         :param url: URL for the new :class:`Request` object.
         :param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -660,7 +658,7 @@ class Session(SessionRedirectMixin):
             self.adapters[key] = self.adapters.pop(key)
 
     def __getstate__(self):
-        state = dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)
+        state = {attr: getattr(self, attr, None) for attr in self.__attrs__}
         state['redirect_cache'] = dict(self.redirect_cache)
         return state
 
diff --git a/python/requests/requests/status_codes.py b/python/requests/requests/status_codes.py
index a852574a45..101b6ff8bb 100644
--- a/python/requests/requests/status_codes.py
+++ b/python/requests/requests/status_codes.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 from .structures import LookupDict
 
 _codes = {
diff --git a/python/requests/requests/structures.py b/python/requests/requests/structures.py
index 3e5f2faa2e..4f941e520f 100644
--- a/python/requests/requests/structures.py
+++ b/python/requests/requests/structures.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.structures
 ~~~~~~~~~~~~~~~~~~~
@@ -9,14 +7,15 @@ Data structures that power Requests.
 """
 
 import collections
+import collections.abc
 
 
-class CaseInsensitiveDict(collections.MutableMapping):
+class CaseInsensitiveDict(collections.abc.MutableMapping):
     """
     A case-insensitive ``dict``-like object.
 
     Implements all methods and operations of
-    ``collections.MutableMapping`` as well as dict's ``copy``. Also
+    ``collections.abc.MutableMapping`` as well as dict's ``copy``. Also
     provides ``lower_items``.
 
     All keys are expected to be strings. The structure remembers the
@@ -71,7 +70,7 @@ class CaseInsensitiveDict(collections.MutableMapping):
         )
 
     def __eq__(self, other):
-        if isinstance(other, collections.Mapping):
+        if isinstance(other, collections.abc.Mapping):
             other = CaseInsensitiveDict(other)
         else:
             return NotImplemented
@@ -80,17 +79,17 @@ class CaseInsensitiveDict(collections.MutableMapping):
 
     # Copy is required
     def copy(self):
-        return CaseInsensitiveDict(self._store.values())
+        return CaseInsensitiveDict(list(self._store.values()))
 
     def __repr__(self):
-        return str(dict(self.items()))
+        return str(dict(list(self.items())))
 
 class LookupDict(dict):
     """Dictionary lookup object."""
 
     def __init__(self, name=None):
         self.name = name
-        super(LookupDict, self).__init__()
+        super().__init__()
 
     def __repr__(self):
         return '<lookup \'%s\'>' % (self.name)
diff --git a/python/requests/requests/utils.py b/python/requests/requests/utils.py
index c5c3fd01d9..9131b7aac7 100644
--- a/python/requests/requests/utils.py
+++ b/python/requests/requests/utils.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 """
 requests.utils
 ~~~~~~~~~~~~~~
@@ -26,7 +24,7 @@ from . import certs
 from .compat import parse_http_list as _parse_list_header
 from .compat import (quote, urlparse, bytes, str, OrderedDict, unquote, is_py2,
                      builtin_str, getproxies, proxy_bypass, urlunparse,
-                     basestring)
+                     str)
 from .cookies import RequestsCookieJar, cookiejar_from_dict
 from .structures import CaseInsensitiveDict
 from .exceptions import InvalidURL, FileModeWarning
@@ -42,7 +40,7 @@ def dict_to_sequence(d):
     """Returns an internal sequence dictionary update."""
 
     if hasattr(d, 'items'):
-        d = d.items()
+        d = list(d.items())
 
     return d
 
@@ -98,7 +96,7 @@ def get_netrc_auth(url, raise_errors=False):
 
         for f in NETRC_FILES:
             try:
-                loc = os.path.expanduser('~/{0}'.format(f))
+                loc = os.path.expanduser('~/{}'.format(f))
             except KeyError:
                 # os.path.expanduser can fail when $HOME is undefined and
                 # getpwuid fails. See http://bugs.python.org/issue20164 &
@@ -128,7 +126,7 @@ def get_netrc_auth(url, raise_errors=False):
                 # Return with login / password
                 login_i = (0 if _netrc[0] else 1)
                 return (_netrc[login_i], _netrc[2])
-        except (NetrcParseError, IOError):
+        except (NetrcParseError, OSError):
             # If there was a parsing error or a permissions issue reading the file,
             # we'll just skip netrc auth unless explicitly asked to raise errors.
             if raise_errors:
@@ -142,7 +140,7 @@ def get_netrc_auth(url, raise_errors=False):
 def guess_filename(obj):
     """Tries to guess the filename of the given object."""
     name = getattr(obj, 'name', None)
-    if (name and isinstance(name, basestring) and name[0] != '<' and
+    if (name and isinstance(name, str) and name[0] != '<' and
             name[-1] != '>'):
         return os.path.basename(name)
 
@@ -189,8 +187,8 @@ def to_key_val_list(value):
     if isinstance(value, (str, bytes, bool, int)):
         raise ValueError('cannot encode objects that are not 2-tuples')
 
-    if isinstance(value, collections.Mapping):
-        value = value.items()
+    if isinstance(value, collections.abc.Mapping):
+        value = list(value.items())
 
     return list(value)
 
@@ -355,8 +353,7 @@ def stream_decode_response_unicode(iterator, r):
     """Stream decodes a iterator."""
 
     if r.encoding is None:
-        for item in iterator:
-            yield item
+        yield from iterator
         return
 
     decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace')
@@ -485,7 +482,7 @@ def dotted_netmask(mask):
 def is_ipv4_address(string_ip):
     try:
         socket.inet_aton(string_ip)
-    except socket.error:
+    except OSError:
         return False
     return True
 
@@ -503,7 +500,7 @@ def is_valid_cidr(string_network):
 
         try:
             socket.inet_aton(string_network.split('/')[0])
-        except socket.error:
+        except OSError:
             return False
     else:
         return False
@@ -579,7 +576,7 @@ def select_proxy(url, proxies):
 
 def default_user_agent(name="python-requests"):
     """Return a string representing the default user agent."""
-    return '%s/%s' % (name, __version__)
+    return '{}/{}'.format(name, __version__)
 
 
 def default_headers():
diff --git a/python/requests/setup.py b/python/requests/setup.py
index b7ed12ba2c..3d0613c78a 100755
--- a/python/requests/setup.py
+++ b/python/requests/setup.py
@@ -29,7 +29,7 @@ packages = [
 requires = []
 
 version = ''
-with open('requests/__init__.py', 'r') as fd:
+with open('requests/__init__.py') as fd:
     version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
                         fd.read(), re.MULTILINE).group(1)
 
diff --git a/python/requests/test_requests.py b/python/requests/test_requests.py
index 0795241867..25f0f2f832 100755
--- a/python/requests/test_requests.py
+++ b/python/requests/test_requests.py
@@ -1,9 +1,7 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 """Tests for Requests."""
 
-from __future__ import division
 import json
 import os
 import pickle
@@ -74,7 +72,7 @@ def httpsbin_url(httpbin_secure):
 # listening on that port)
 TARPIT = "http://10.255.255.1"
 
-class TestRequests(object):
+class TestRequests:
 
     _multiprocess_can_split_ = True
 
@@ -159,7 +157,7 @@ class TestRequests(object):
 
     def test_binary_put(self):
         request = requests.Request('PUT', 'http://example.com',
-                                   data=u"ööö".encode("utf-8")).prepare()
+                                   data="ööö".encode()).prepare()
         assert isinstance(request.body, bytes)
 
     def test_mixed_case_scheme_acceptable(self, httpbin):
@@ -171,7 +169,7 @@ class TestRequests(object):
             url = scheme + parts.netloc + parts.path
             r = requests.Request('GET', url)
             r = s.send(r.prepare())
-            assert r.status_code == 200, 'failed for scheme {0}'.format(scheme)
+            assert r.status_code == 200, 'failed for scheme {}'.format(scheme)
 
     def test_HTTP_200_OK_GET_ALTERNATIVE(self, httpbin):
         r = requests.Request('GET', httpbin('get'))
@@ -523,7 +521,7 @@ class TestRequests(object):
     def test_unicode_header_name(self, httpbin):
         requests.put(
             httpbin('put'),
-            headers={str('Content-Type'): 'application/octet-stream'},
+            headers={'Content-Type': 'application/octet-stream'},
             data='\xff')  # compat.str is unicode.
 
     def test_pyopenssl_redirect(self, httpsbin_url, httpbin_ca_bundle):
@@ -559,7 +557,7 @@ class TestRequests(object):
         assert r.status_code == 200
 
         r = requests.post(httpbin('post'),
-            data={'stuff': 'elixr'.encode('utf-8')},
+            data={'stuff': b'elixr'},
             files={'file': ('test_requests.py', open(__file__, 'rb'))})
         assert r.status_code == 200
 
@@ -567,7 +565,7 @@ class TestRequests(object):
         filename = os.path.splitext(__file__)[0] + '.py'
         r = requests.Request(method='POST',
                              url=httpbin('post'),
-                             data={'stuff'.encode('utf-8'): 'elixr'},
+                             data={b'stuff': 'elixr'},
                              files={'file': ('test_requests.py',
                                              open(filename, 'rb'))})
         prep = r.prepare()
@@ -719,8 +717,8 @@ class TestRequests(object):
         jar.set(key1, value1)
 
         d1 = dict(jar)
-        d2 = dict(jar.iteritems())
-        d3 = dict(jar.items())
+        d2 = dict(jar.items())
+        d3 = dict(list(jar.items()))
 
         assert len(jar) == 2
         assert len(d1) == 2
@@ -739,8 +737,8 @@ class TestRequests(object):
         jar.set(key1, value1)
 
         d1 = dict(jar)
-        d2 = dict(jar.iteritems())
-        d3 = dict(jar.items())
+        d2 = dict(jar.items())
+        d3 = dict(list(jar.items()))
 
         assert d1['some_cookie'] == 'some_value'
         assert d2['some_cookie'] == 'some_value'
@@ -757,7 +755,7 @@ class TestRequests(object):
         jar.set(key, value)
         jar.set(key1, value1)
 
-        keys = jar.keys()
+        keys = list(jar.keys())
         assert keys == list(keys)
         # make sure one can use keys multiple times
         assert list(keys) == list(keys)
@@ -773,7 +771,7 @@ class TestRequests(object):
         jar.set(key, value)
         jar.set(key1, value1)
 
-        values = jar.values()
+        values = list(jar.values())
         assert values == list(values)
         # make sure one can use values multiple times
         assert list(values) == list(values)
@@ -789,7 +787,7 @@ class TestRequests(object):
         jar.set(key, value)
         jar.set(key1, value1)
 
-        items = jar.items()
+        items = list(jar.items())
         assert items == list(items)
         # make sure one can use items multiple times
         assert list(items) == list(items)
@@ -962,7 +960,7 @@ class TestRequests(object):
         assert r.json()['args'] == {'foo': 'bar', 'FOO': 'bar'}
 
     def test_long_authinfo_in_url(self):
-        url = 'http://{0}:{1}@{2}:9000/path?query#frag'.format(
+        url = 'http://{}:{}@{}:9000/path?query#frag'.format(
             'E8A3BE87-9E3F-4620-8858-95478E385B5B',
             'EA770032-DA4D-4D84-8CE9-29C6D910BF1E',
             'exactly-------------sixty-----------three------------characters',
@@ -971,14 +969,14 @@ class TestRequests(object):
         assert r.url == url
 
     def test_header_keys_are_native(self, httpbin):
-        headers = {u('unicode'): 'blah', 'byte'.encode('ascii'): 'blah'}
+        headers = {u('unicode'): 'blah', b'byte': 'blah'}
         r = requests.Request('GET', httpbin('get'), headers=headers)
         p = r.prepare()
 
         # This is testing that they are builtin strings. A bit weird, but there
         # we go.
-        assert 'unicode' in p.headers.keys()
-        assert 'byte' in p.headers.keys()
+        assert 'unicode' in list(p.headers.keys())
+        assert 'byte' in list(p.headers.keys())
 
     def test_can_send_nonstring_objects_with_files(self, httpbin):
         data = {'a': 0.0}
@@ -1306,7 +1304,7 @@ class TestCaseInsensitiveDict(unittest.TestCase):
         })
         keyset = frozenset(['Accept', 'user-Agent'])
         assert frozenset(i[0] for i in cid.items()) == keyset
-        assert frozenset(cid.keys()) == keyset
+        assert frozenset(list(cid.keys())) == keyset
         assert frozenset(cid) == keyset
 
     def test_preserve_last_key_case(self):
@@ -1318,7 +1316,7 @@ class TestCaseInsensitiveDict(unittest.TestCase):
         cid['USER-AGENT'] = 'requests'
         keyset = frozenset(['ACCEPT', 'USER-AGENT'])
         assert frozenset(i[0] for i in cid.items()) == keyset
-        assert frozenset(cid.keys()) == keyset
+        assert frozenset(list(cid.keys())) == keyset
         assert frozenset(cid) == keyset
 
     def test_copy(self):
@@ -1731,7 +1729,7 @@ def test_urllib3_pool_connection_closed(httpbin):
     try:
         s.get(httpbin('status/200'))
     except ConnectionError as e:
-        assert u"Pool is closed." in str(e)
+        assert "Pool is closed." in str(e)
 
 
 def test_vendor_aliases():
diff --git a/python/rsa/create_timing_table.py b/python/rsa/create_timing_table.py
index b1b2871b3d..b37f20ae52 100755
--- a/python/rsa/create_timing_table.py
+++ b/python/rsa/create_timing_table.py
@@ -20,7 +20,7 @@ def run_speed_test(bitsize):
     duration = end - start
     dur_per_call = duration / iterations
 
-    print '%5i bit: %9.3f sec. (%i iterations over %.1f seconds)' % (bitsize,
+    print('%5i bit: %9.3f sec. (%i iterations over %.1f seconds)' % (bitsize,)
             dur_per_call, iterations, duration)
 
 for bitsize in (128, 256, 384, 512, 1024, 2048, 3072, 4096):
diff --git a/python/rsa/rsa/__init__.py b/python/rsa/rsa/__init__.py
index 2d01c12e0f..305ccf56be 100644
--- a/python/rsa/rsa/__init__.py
+++ b/python/rsa/rsa/__init__.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/rsa/_compat.py b/python/rsa/rsa/_compat.py
index 3c4eb81b13..8dc522c3a5 100644
--- a/python/rsa/rsa/_compat.py
+++ b/python/rsa/rsa/_compat.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -17,7 +16,6 @@
 """Python compatibility wrappers."""
 
 
-from __future__ import absolute_import
 
 import sys
 from struct import pack
@@ -25,7 +23,7 @@ from struct import pack
 try:
     MAX_INT = sys.maxsize
 except AttributeError:
-    MAX_INT = sys.maxint
+    MAX_INT = sys.maxsize
 
 MAX_INT64 = (1 << 63) - 1
 MAX_INT32 = (1 << 31) - 1
@@ -45,7 +43,7 @@ else:
 
 try:
     # < Python3
-    unicode_type = unicode
+    unicode_type = str
     have_python3 = False
 except NameError:
     # Python3.
@@ -62,7 +60,7 @@ else:
 
 # ``long`` is no more. Do type detection using this instead.
 try:
-    integer_types = (int, long)
+    integer_types = int
 except NameError:
     integer_types = (int,)
 
diff --git a/python/rsa/rsa/_version133.py b/python/rsa/rsa/_version133.py
index 230a03c84b..65aa3ede92 100644
--- a/python/rsa/rsa/_version133.py
+++ b/python/rsa/rsa/_version133.py
@@ -18,7 +18,7 @@ __version__ = '1.3.3'
 # NOTE: Python's modulo can return negative numbers. We compensate for
 # this behaviour using the abs() function
 
-from cPickle import dumps, loads
+from six.moves.cPickle import dumps, loads
 import base64
 import math
 import os
@@ -55,14 +55,14 @@ def bytes2int(bytes):
     8405007
     """
 
-    if not (type(bytes) is types.ListType or type(bytes) is types.StringType):
+    if not (type(bytes) is list or type(bytes) is bytes):
         raise TypeError("You must pass a string or a list")
 
     # Convert byte stream to integer
     integer = 0
     for byte in bytes:
         integer *= 256
-        if type(byte) is types.StringType: byte = ord(byte)
+        if type(byte) is bytes: byte = ord(byte)
         integer += byte
 
     return integer
@@ -74,13 +74,13 @@ def int2bytes(number):
     123456789
     """
 
-    if not (type(number) is types.LongType or type(number) is types.IntType):
+    if not (type(number) is int or type(number) is int):
         raise TypeError("You must pass a long or an int")
 
     string = ""
 
     while number > 0:
-        string = "%s%s" % (byte(number & 0xFF), string)
+        string = "{}{}".format(byte(number & 0xFF), string)
         number /= 256
     
     return string
@@ -268,7 +268,7 @@ def extended_euclid_gcd(a, b):
         return (a, 1, 0)
 
     q = abs(a % b)
-    r = long(a / b)
+    r = int(a / b)
     (d, k, l) = extended_euclid_gcd(b, q)
 
     return (d, l, k - l*r)
@@ -330,10 +330,10 @@ def encrypt_int(message, ekey, n):
     """Encrypts a message using encryption key 'ekey', working modulo
     n"""
 
-    if type(message) is types.IntType:
-        return encrypt_int(long(message), ekey, n)
+    if type(message) is int:
+        return encrypt_int(int(message), ekey, n)
 
-    if not type(message) is types.LongType:
+    if not type(message) is int:
         raise TypeError("You must pass a long or an int")
 
     if message > 0 and \
diff --git a/python/rsa/rsa/_version200.py b/python/rsa/rsa/_version200.py
index f915653857..4b047c320e 100644
--- a/python/rsa/rsa/_version200.py
+++ b/python/rsa/rsa/_version200.py
@@ -52,14 +52,14 @@ def bytes2int(bytes):
     8405007
     """
 
-    if not (type(bytes) is types.ListType or type(bytes) is types.StringType):
+    if not (type(bytes) is list or type(bytes) is bytes):
         raise TypeError("You must pass a string or a list")
 
     # Convert byte stream to integer
     integer = 0
     for byte in bytes:
         integer *= 256
-        if type(byte) is types.StringType: byte = ord(byte)
+        if type(byte) is bytes: byte = ord(byte)
         integer += byte
 
     return integer
@@ -69,13 +69,13 @@ def int2bytes(number):
     Converts a number to a string of bytes
     """
 
-    if not (type(number) is types.LongType or type(number) is types.IntType):
+    if not (type(number) is int or type(number) is int):
         raise TypeError("You must pass a long or an int")
 
     string = ""
 
     while number > 0:
-        string = "%s%s" % (byte(number & 0xFF), string)
+        string = "{}{}".format(byte(number & 0xFF), string)
         number /= 256
     
     return string
@@ -88,7 +88,7 @@ def to64(number):
     'A'
     """
 
-    if not (type(number) is types.LongType or type(number) is types.IntType):
+    if not (type(number) is int or type(number) is int):
         raise TypeError("You must pass a long or an int")
 
     if 0 <= number <= 9:            #00-09 translates to '0' - '9'
@@ -117,7 +117,7 @@ def from64(number):
     1
     """
 
-    if not (type(number) is types.LongType or type(number) is types.IntType):
+    if not (type(number) is int or type(number) is int):
         raise TypeError("You must pass a long or an int")
 
     if 48 <= number <= 57:         #ord('0') - ord('9') translates to 0-9
@@ -146,13 +146,13 @@ def int2str64(number):
     '7MyqL'
     """
 
-    if not (type(number) is types.LongType or type(number) is types.IntType):
+    if not (type(number) is int or type(number) is int):
         raise TypeError("You must pass a long or an int")
 
     string = ""
 
     while number > 0:
-        string = "%s%s" % (to64(number & 0x3F), string)
+        string = "{}{}".format(to64(number & 0x3F), string)
         number /= 64
 
     return string
@@ -166,13 +166,13 @@ def str642int(string):
     123456789
     """
 
-    if not (type(string) is types.ListType or type(string) is types.StringType):
+    if not (type(string) is list or type(string) is bytes):
         raise TypeError("You must pass a string or a list")
 
     integer = 0
     for byte in string:
         integer *= 64
-        if type(byte) is types.StringType: byte = ord(byte)
+        if type(byte) is bytes: byte = ord(byte)
         integer += from64(byte)
 
     return integer
@@ -333,7 +333,7 @@ def extended_gcd(a, b):
     oa = a                             #Remember original a/b to remove 
     ob = b                             #negative values from return results
     while b != 0:
-        q = long(a/b)
+        q = int(a/b)
         (a, b)  = (b, a % b)
         (x, lx) = ((lx - (q * x)),x)
         (y, ly) = ((ly - (q * y)),y)
@@ -393,10 +393,10 @@ def newkeys(nbits):
 def encrypt_int(message, ekey, n):
     """Encrypts a message using encryption key 'ekey', working modulo n"""
 
-    if type(message) is types.IntType:
-        message = long(message)
+    if type(message) is int:
+        message = int(message)
 
-    if not type(message) is types.LongType:
+    if not type(message) is int:
         raise TypeError("You must pass a long or int")
 
     if message < 0 or message > n:
diff --git a/python/rsa/rsa/bigfile.py b/python/rsa/rsa/bigfile.py
index 516cf56b51..87a861581b 100644
--- a/python/rsa/rsa/bigfile.py
+++ b/python/rsa/rsa/bigfile.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/rsa/cli.py b/python/rsa/rsa/cli.py
index 527cc4979a..afff615ea1 100644
--- a/python/rsa/rsa/cli.py
+++ b/python/rsa/rsa/cli.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -19,7 +18,6 @@
 These scripts are called by the executables defined in setup.py.
 '''
 
-from __future__ import with_statement, print_function
 
 import abc
 import sys
@@ -87,7 +85,7 @@ def keygen():
         sys.stdout.write(data)
 
 
-class CryptoOperation(object):
+class CryptoOperation:
     '''CLI callable that operates with input, output, and a key.'''
 
     __metaclass__ = abc.ABCMeta
@@ -164,7 +162,7 @@ class CryptoOperation(object):
     def read_key(self, filename, keyform):
         '''Reads a public or private key.'''
 
-        print('Reading %s key from %s' % (self.keyname, filename), file=sys.stderr)
+        print('Reading {} key from {}'.format(self.keyname, filename), file=sys.stderr)
         with open(filename, 'rb') as keyfile:
             keydata = keyfile.read()
 
diff --git a/python/rsa/rsa/common.py b/python/rsa/rsa/common.py
index 39feb8c228..216259f7f4 100644
--- a/python/rsa/rsa/common.py
+++ b/python/rsa/rsa/common.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/rsa/core.py b/python/rsa/rsa/core.py
index 90dfee8e57..a1a4786b1a 100644
--- a/python/rsa/rsa/core.py
+++ b/python/rsa/rsa/core.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -28,7 +27,7 @@ def assert_int(var, name):
     if is_integer(var):
         return
 
-    raise TypeError('%s should be an integer, not %s' % (name, var.__class__))
+    raise TypeError('{} should be an integer, not {}'.format(name, var.__class__))
 
 def encrypt_int(message, ekey, n):
     '''Encrypts a message using encryption key 'ekey', working modulo n'''
diff --git a/python/rsa/rsa/key.py b/python/rsa/rsa/key.py
index b6de7b3f3b..0615f392e8 100644
--- a/python/rsa/rsa/key.py
+++ b/python/rsa/rsa/key.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -25,6 +24,7 @@ of pyasn1.
 
 '''
 
+from __future__ import print_function
 import logging
 from rsa._compat import b, bytes_type
 
@@ -36,7 +36,7 @@ log = logging.getLogger(__name__)
 
 
 
-class AbstractKey(object):
+class AbstractKey:
     '''Abstract superclass for private and public keys.'''
 
     @classmethod
@@ -58,7 +58,7 @@ class AbstractKey(object):
 
         if format not in methods:
             formats = ', '.join(sorted(methods.keys()))
-            raise ValueError('Unsupported format: %r, try one of %s' % (format,
+            raise ValueError('Unsupported format: {!r}, try one of {}'.format(format,
                 formats))
 
         method = methods[format]
@@ -79,7 +79,7 @@ class AbstractKey(object):
 
         if format not in methods:
             formats = ', '.join(sorted(methods.keys()))
-            raise ValueError('Unsupported format: %r, try one of %s' % (format,
+            raise ValueError('Unsupported format: {!r}, try one of {}'.format(format,
                 formats))
 
         method = methods[format]
@@ -605,7 +605,7 @@ if __name__ == '__main__':
                 break
 
             if (count and count % 10 == 0) or count == 1:
-                print('%i times' % count)
+                print(('%i times' % count))
     except KeyboardInterrupt:
         print('Aborted')
     else:
diff --git a/python/rsa/rsa/parallel.py b/python/rsa/rsa/parallel.py
index e5034ac707..a170358461 100644
--- a/python/rsa/rsa/parallel.py
+++ b/python/rsa/rsa/parallel.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -24,8 +23,8 @@ Introduced in Python-RSA 3.1.
 
 '''
 
-from __future__ import print_function
 
+from __future__ import print_function
 import multiprocessing as mp
 
 import rsa.prime
@@ -88,7 +87,7 @@ if __name__ == '__main__':
             break
         
         if count and count % 10 == 0:
-            print('%i times' % count)
+            print(('%i times' % count))
     
     print('Doctests done')
 
diff --git a/python/rsa/rsa/pem.py b/python/rsa/rsa/pem.py
index b1c3a0edb4..d47534619a 100644
--- a/python/rsa/rsa/pem.py
+++ b/python/rsa/rsa/pem.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/rsa/pkcs1.py b/python/rsa/rsa/pkcs1.py
index 15e4cf639e..5dc33d87d4 100644
--- a/python/rsa/rsa/pkcs1.py
+++ b/python/rsa/rsa/pkcs1.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -28,6 +27,7 @@ can be used to deduce where in the process the failure occurred. DO NOT PASS
 SUCH INFORMATION to your users.
 '''
 
+from __future__ import print_function
 import hashlib
 import os
 
@@ -386,6 +386,6 @@ if __name__ == '__main__':
             break
         
         if count and count % 100 == 0:
-            print('%i times' % count)
+            print(('%i times' % count))
     
     print('Doctests done')
diff --git a/python/rsa/rsa/prime.py b/python/rsa/rsa/prime.py
index 7422eb1d28..574d413bae 100644
--- a/python/rsa/rsa/prime.py
+++ b/python/rsa/rsa/prime.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -20,6 +19,7 @@ Implementation based on the book Algorithm Design by Michael T. Goodrich and
 Roberto Tamassia, 2002.
 '''
 
+from __future__ import print_function
 __all__ = [ 'getprime', 'are_relatively_prime']
 
 import rsa.randnum
@@ -161,6 +161,6 @@ if __name__ == '__main__':
             break
         
         if count and count % 100 == 0:
-            print('%i times' % count)
+            print(('%i times' % count))
     
     print('Doctests done')
diff --git a/python/rsa/rsa/randnum.py b/python/rsa/rsa/randnum.py
index 0e782744c0..16c2bdaafd 100644
--- a/python/rsa/rsa/randnum.py
+++ b/python/rsa/rsa/randnum.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/rsa/transform.py b/python/rsa/rsa/transform.py
index c740b2d275..ebdca1f1d9 100644
--- a/python/rsa/rsa/transform.py
+++ b/python/rsa/rsa/transform.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -19,7 +18,6 @@
 From bytes to a number, number to bytes, etc.
 '''
 
-from __future__ import absolute_import
 
 try:
     # We'll use psyco if available on 32-bit architectures to speed up code.
diff --git a/python/rsa/rsa/util.py b/python/rsa/rsa/util.py
index 5bbb70be18..5c34c57ee2 100644
--- a/python/rsa/rsa/util.py
+++ b/python/rsa/rsa/util.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
@@ -16,7 +15,6 @@
 
 '''Utility functions.'''
 
-from __future__ import with_statement, print_function
 
 import sys
 from optparse import OptionParser
diff --git a/python/rsa/rsa/varblock.py b/python/rsa/rsa/varblock.py
index c7d96ae6a7..563873a48a 100644
--- a/python/rsa/rsa/varblock.py
+++ b/python/rsa/rsa/varblock.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 #  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
 #
diff --git a/python/rsa/run_tests.py b/python/rsa/run_tests.py
index e0f249081f..577c95a495 100644
--- a/python/rsa/run_tests.py
+++ b/python/rsa/run_tests.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 import os
 import sys
diff --git a/python/rsa/tests/constants.py b/python/rsa/tests/constants.py
index 6a0d081836..7159fd66f9 100644
--- a/python/rsa/tests/constants.py
+++ b/python/rsa/tests/constants.py
@@ -1,9 +1,7 @@
-# -*- coding: utf-8 -*-
-
 from rsa._compat import have_python3
 
 if have_python3:
-    from py3kconstants import *
+    from .py3kconstants import *
 else:
-    from py2kconstants import *
+    from .py2kconstants import *
 
diff --git a/python/rsa/tests/py2kconstants.py b/python/rsa/tests/py2kconstants.py
index 5f695dd227..9c52637d2a 100644
--- a/python/rsa/tests/py2kconstants.py
+++ b/python/rsa/tests/py2kconstants.py
@@ -1,3 +1 @@
-# -*- coding: utf-8 -*-
-
-unicode_string = u"Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+unicode_string = "Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ"
diff --git a/python/rsa/tests/py3kconstants.py b/python/rsa/tests/py3kconstants.py
index 83b67129c9..9c52637d2a 100644
--- a/python/rsa/tests/py3kconstants.py
+++ b/python/rsa/tests/py3kconstants.py
@@ -1,3 +1 @@
-# -*- coding: utf-8 -*-
-
 unicode_string = "Euro=\u20ac ABCDEFGHIJKLMNOPQRSTUVWXYZ"
diff --git a/python/rsa/tests/test_bigfile.py b/python/rsa/tests/test_bigfile.py
index 86bcbbac6f..a09bf83976 100644
--- a/python/rsa/tests/test_bigfile.py
+++ b/python/rsa/tests/test_bigfile.py
@@ -31,7 +31,7 @@ class BigfileTest(unittest2.TestCase):
         clearfile = BytesIO()
 
         bigfile.decrypt_bigfile(cryptfile, clearfile, priv_key)
-        self.assertEquals(clearfile.getvalue(), message)
+        self.assertEqual(clearfile.getvalue(), message)
         
         # We have 2x6 bytes in the message, so that should result in two
         # bigfile.
diff --git a/python/rsa/tests/test_common.py b/python/rsa/tests/test_common.py
index d105dc020f..00d871b012 100644
--- a/python/rsa/tests/test_common.py
+++ b/python/rsa/tests/test_common.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 import unittest2
 import struct
diff --git a/python/rsa/tests/test_compat.py b/python/rsa/tests/test_compat.py
index 3652c82d51..cfa2c2b2d1 100644
--- a/python/rsa/tests/test_compat.py
+++ b/python/rsa/tests/test_compat.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 import unittest2
 import struct
 
diff --git a/python/rsa/tests/test_integers.py b/python/rsa/tests/test_integers.py
index 0a712aa0fc..8f75829779 100644
--- a/python/rsa/tests/test_integers.py
+++ b/python/rsa/tests/test_integers.py
@@ -1,5 +1,6 @@
 '''Tests integer operations.'''
 
+from __future__ import print_function
 import unittest2
 
 import rsa.core
@@ -12,13 +13,13 @@ class IntegerTest(unittest2.TestCase):
     def test_enc_dec(self):
 
         message = 42
-        print("\tMessage:   %d" % message)
+        print(("\tMessage:   %d" % message))
 
         encrypted = rsa.core.encrypt_int(message, self.pub.e, self.pub.n)
-        print("\tEncrypted: %d" % encrypted)
+        print(("\tEncrypted: %d" % encrypted))
 
         decrypted = rsa.core.decrypt_int(encrypted, self.priv.d, self.pub.n)
-        print("\tDecrypted: %d" % decrypted)
+        print(("\tDecrypted: %d" % decrypted))
 
         self.assertEqual(message, decrypted)
 
@@ -27,10 +28,10 @@ class IntegerTest(unittest2.TestCase):
         message = 42
 
         signed = rsa.core.encrypt_int(message,self.priv.d, self.pub.n)
-        print("\tSigned:    %d" % signed)
+        print(("\tSigned:    %d" % signed))
 
         verified = rsa.core.decrypt_int(signed, self.pub.e,self.pub.n)
-        print("\tVerified:  %d" % verified)
+        print(("\tVerified:  %d" % verified))
 
         self.assertEqual(message, verified)
 
diff --git a/python/rsa/tests/test_pem.py b/python/rsa/tests/test_pem.py
index 867f678a0e..acfd3670b4 100644
--- a/python/rsa/tests/test_pem.py
+++ b/python/rsa/tests/test_pem.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 
 import unittest2
diff --git a/python/rsa/tests/test_pkcs1.py b/python/rsa/tests/test_pkcs1.py
index d5882dfd1b..dea45c85c2 100644
--- a/python/rsa/tests/test_pkcs1.py
+++ b/python/rsa/tests/test_pkcs1.py
@@ -1,5 +1,6 @@
 '''Tests string operations.'''
 
+from __future__ import print_function
 import struct
 import unittest2
 
@@ -15,13 +16,13 @@ class BinaryTest(unittest2.TestCase):
     def test_enc_dec(self):
 
         message = struct.pack('>IIII', 0, 0, 0, 1)
-        print("\tMessage:   %r" % message)
+        print(("\tMessage:   %r" % message))
 
         encrypted = pkcs1.encrypt(message, self.pub)
-        print("\tEncrypted: %r" % encrypted)
+        print(("\tEncrypted: %r" % encrypted))
 
         decrypted = pkcs1.decrypt(encrypted, self.priv)
-        print("\tDecrypted: %r" % decrypted)
+        print(("\tDecrypted: %r" % decrypted))
 
         self.assertEqual(message, decrypted)
 
@@ -59,10 +60,10 @@ class SignatureTest(unittest2.TestCase):
         '''Test happy flow of sign and verify'''
         
         message = b('je moeder')
-        print("\tMessage:   %r" % message)
+        print(("\tMessage:   %r" % message))
 
         signature = pkcs1.sign(message, self.priv, 'SHA-256')
-        print("\tSignature: %r" % signature)
+        print(("\tSignature: %r" % signature))
 
         self.assertTrue(pkcs1.verify(message, signature, self.pub))
 
diff --git a/python/rsa/tests/test_strings.py b/python/rsa/tests/test_strings.py
index 4af06291d4..2762dd3d9f 100644
--- a/python/rsa/tests/test_strings.py
+++ b/python/rsa/tests/test_strings.py
@@ -1,12 +1,12 @@
 '''Tests string operations.'''
 
-from __future__ import absolute_import
 
+from __future__ import print_function
 import unittest2
 
 import rsa
 
-from constants import unicode_string
+from .constants import unicode_string
 
 class StringTest(unittest2.TestCase):
 
@@ -16,13 +16,13 @@ class StringTest(unittest2.TestCase):
     def test_enc_dec(self):
 
         message = unicode_string.encode('utf-8')
-        print("\tMessage:   %s" % message)
+        print(("\tMessage:   %s" % message))
 
         encrypted = rsa.encrypt(message, self.pub)
-        print("\tEncrypted: %s" % encrypted)
+        print(("\tEncrypted: %s" % encrypted))
 
         decrypted = rsa.decrypt(encrypted, self.priv)
-        print("\tDecrypted: %s" % decrypted)
+        print(("\tDecrypted: %s" % decrypted))
 
         self.assertEqual(message, decrypted)
 
diff --git a/python/rsa/tests/test_transform.py b/python/rsa/tests/test_transform.py
index ffd9ec892a..392e824774 100644
--- a/python/rsa/tests/test_transform.py
+++ b/python/rsa/tests/test_transform.py
@@ -1,6 +1,3 @@
-# -*- coding: utf-8 -*-
-
-
 import unittest2
 from rsa._compat import b
 from rsa.transform import int2bytes, bytes2int, _int2bytes
diff --git a/python/slugid/setup.py b/python/slugid/setup.py
index d7c8b328bd..229849952b 100644
--- a/python/slugid/setup.py
+++ b/python/slugid/setup.py
@@ -14,7 +14,7 @@ packages = [
 ]
 
 version = ''
-with open('slugid/__init__.py', 'r') as fd:
+with open('slugid/__init__.py') as fd:
     version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
                         fd.read(), re.MULTILINE).group(1)
 
diff --git a/python/slugid/slugid/__init__.py b/python/slugid/slugid/__init__.py
index ca7de07e24..4d5b75b906 100644
--- a/python/slugid/slugid/__init__.py
+++ b/python/slugid/slugid/__init__.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 #    **************
 #    * Slugid API *
 #    **************
diff --git a/python/virtualenv/bin/rebuild-script.py b/python/virtualenv/bin/rebuild-script.py
index a816af3eb7..81b654ec79 100755
--- a/python/virtualenv/bin/rebuild-script.py
+++ b/python/virtualenv/bin/rebuild-script.py
@@ -2,7 +2,6 @@
 """
 Helper script to rebuild virtualenv.py from virtualenv_support
 """
-from __future__ import print_function
 
 import os
 import re
diff --git a/python/virtualenv/docs/conf.py b/python/virtualenv/docs/conf.py
index 9332aa1bc7..33920cf0d3 100644
--- a/python/virtualenv/docs/conf.py
+++ b/python/virtualenv/docs/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # Paste documentation build configuration file, created by
 # sphinx-quickstart on Tue Apr 22 22:08:49 2008.
diff --git a/python/virtualenv/setup.py b/python/virtualenv/setup.py
index ee03bc5313..9d738d6b62 100644
--- a/python/virtualenv/setup.py
+++ b/python/virtualenv/setup.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import os
 import re
 import shutil
diff --git a/python/virtualenv/site.py b/python/virtualenv/site.py
index bf23c19204..75a16b47a1 100644
--- a/python/virtualenv/site.py
+++ b/python/virtualenv/site.py
@@ -63,12 +63,13 @@ ImportError exception, it is silently ignored.
 
 """
 
+from __future__ import print_function
 import sys
 import os
 import platform
 
 try:
-    import __builtin__ as builtins
+    import builtins as builtins
 except ImportError:
     import builtins
 try:
@@ -139,7 +140,7 @@ def addbuilddir():
     """Append ./build/lib.<platform> in case we're running in the build dir
     (especially for Guido :-)"""
     from distutils.util import get_platform
-    s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
+    s = "build/lib.{}-{:.3}".format(get_platform(), sys.version)
     if hasattr(sys, 'gettotalrefcount'):
         s += '-pydebug'
     s = os.path.join(os.path.dirname(sys.path[-1]), s)
@@ -167,8 +168,8 @@ def addpackage(sitedir, name, known_paths):
         reset = 0
     fullname = os.path.join(sitedir, name)
     try:
-        f = open(fullname, "rU")
-    except IOError:
+        f = open(fullname)
+    except OSError:
         return
     try:
         for line in f:
@@ -201,7 +202,7 @@ def addsitedir(sitedir, known_paths=None):
         sys.path.append(sitedir)        # Add path component
     try:
         names = os.listdir(sitedir)
-    except os.error:
+    except OSError:
         return
     names.sort()
     for name in names:
@@ -393,11 +394,11 @@ def setquit():
     else:
         eof = 'Ctrl-D (i.e. EOF)'
 
-    class Quitter(object):
+    class Quitter:
         def __init__(self, name):
             self.name = name
         def __repr__(self):
-            return 'Use %s() or %s to exit' % (self.name, eof)
+            return 'Use {}() or {} to exit'.format(self.name, eof)
         def __call__(self, code=None):
             # Shells like IDLE catch the SystemExit, but listen when their
             # stdin wrapper is closed.
@@ -410,7 +411,7 @@ def setquit():
     builtins.exit = Quitter('exit')
 
 
-class _Printer(object):
+class _Printer:
     """interactive prompt objects for printing the license text, a list of
     contributors and the copyright notice."""
 
@@ -431,11 +432,11 @@ class _Printer(object):
             for filename in self.__files:
                 filename = os.path.join(dir, filename)
                 try:
-                    fp = open(filename, "rU")
+                    fp = open(filename)
                     data = fp.read()
                     fp.close()
                     break
-                except IOError:
+                except OSError:
                     pass
             if data:
                 break
@@ -458,7 +459,7 @@ class _Printer(object):
         while 1:
             try:
                 for i in range(lineno, lineno + self.MAXLINES):
-                    print(self.__lines[i])
+                    print((self.__lines[i]))
             except IndexError:
                 break
             else:
@@ -466,9 +467,9 @@ class _Printer(object):
                 key = None
                 while key is None:
                     try:
-                        key = raw_input(prompt)
-                    except NameError:
                         key = input(prompt)
+                    except NameError:
+                        key = eval(input(prompt))
                     if key not in ('', 'q'):
                         key = None
                 if key == 'q':
@@ -496,7 +497,7 @@ def setcopyright():
         [os.path.join(here, os.pardir), here, os.curdir])
 
 
-class _Helper(object):
+class _Helper:
     """Define the built-in 'help'.
     This is a wrapper around pydoc.help (with a twist).
 
@@ -727,16 +728,16 @@ def _script():
     if not args:
         print("sys.path = [")
         for dir in sys.path:
-            print("    %r," % (dir,))
+            print(("    {!r},".format(dir)))
         print("]")
         def exists(path):
             if os.path.isdir(path):
                 return "exists"
             else:
                 return "doesn't exist"
-        print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
-        print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
-        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        print(("USER_BASE: {!r} ({})".format(USER_BASE, exists(USER_BASE))))
+        print(("USER_SITE: {!r} ({})".format(USER_SITE, exists(USER_BASE))))
+        print(("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE))
         sys.exit(0)
 
     buffer = []
@@ -746,7 +747,7 @@ def _script():
         buffer.append(USER_SITE)
 
     if buffer:
-        print(os.pathsep.join(buffer))
+        print((os.pathsep.join(buffer)))
         if ENABLE_USER_SITE:
             sys.exit(0)
         elif ENABLE_USER_SITE is False:
@@ -757,7 +758,7 @@ def _script():
             sys.exit(3)
     else:
         import textwrap
-        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        print((textwrap.dedent(help % (sys.argv[0], os.pathsep))))
         sys.exit(10)
 
 if __name__ == '__main__':
diff --git a/python/virtualenv/tests/test_virtualenv.py b/python/virtualenv/tests/test_virtualenv.py
index 756cde9368..57fecf005c 100644
--- a/python/virtualenv/tests/test_virtualenv.py
+++ b/python/virtualenv/tests/test_virtualenv.py
@@ -7,7 +7,7 @@ import tempfile
 import pytest
 import platform  # noqa
 
-from mock import patch, Mock
+from unittest.mock import patch, Mock
 
 
 def test_version():
@@ -110,7 +110,7 @@ def test_install_python_bin():
         else:
             py_exe_no_version = 'python'
             py_exe_version_major = 'python%s' % sys.version_info[0]
-            py_exe_version_major_minor = 'python%s.%s' % (
+            py_exe_version_major_minor = 'python{}.{}'.format(
                 sys.version_info[0], sys.version_info[1])
             required_executables = [ py_exe_no_version, py_exe_version_major,
                                      py_exe_version_major_minor ]
diff --git a/python/virtualenv/virtualenv.py b/python/virtualenv/virtualenv.py
index 60a42e4dcb..f67a642305 100755
--- a/python/virtualenv/virtualenv.py
+++ b/python/virtualenv/virtualenv.py
@@ -1,8 +1,10 @@
 #!/usr/bin/env python
 """Create a "virtual" Python installation"""
 
+from __future__ import print_function
 import os
 import sys
+import six
 
 # If we are running in a new interpreter to create a virtualenv,
 # we do NOT want paths from our existing location interfering with anything,
@@ -32,7 +34,7 @@ from distutils.util import strtobool
 from os.path import join
 
 try:
-    import ConfigParser
+    import six.moves.configparser
 except ImportError:
     import configparser as ConfigParser
 
@@ -40,16 +42,16 @@ __version__ = "15.0.1"
 virtualenv_version = __version__  # legacy
 
 if sys.version_info < (2, 6):
-    print('ERROR: %s' % sys.exc_info()[1])
+    print(('ERROR: %s' % sys.exc_info()[1]))
     print('ERROR: this script requires Python 2.6 or greater.')
     sys.exit(101)
 
 import platform
 
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 is_tauthon = platform.python_implementation() == "Tauthon"
 is_jython = sys.platform.startswith('java')
@@ -60,7 +62,7 @@ is_msys2 = (sys.platform == 'win32' and os.sep == '/')
 is_darwin = (sys.platform == 'darwin')
 abiflags = getattr(sys, 'abiflags', '')
 
-py_version = '%s%s.%s' % ("tauthon" if is_tauthon else "python",
+py_version = '{}{}.{}'.format("tauthon" if is_tauthon else "python",
                           sys.version_info[0], sys.version_info[1])
 
 user_dir = os.path.expanduser('~')
@@ -86,13 +88,13 @@ else:
     try:
         import winreg
     except ImportError:
-        import _winreg as winreg
+        import six.moves.winreg as winreg
 
     def get_installed_pythons():
         try:
             python_core = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE,
                                            "Software\\Python\\PythonCore")
-        except WindowsError:
+        except OSError:
             # No registered Python installations
             return {}
         i = 0
@@ -101,13 +103,13 @@ else:
             try:
                 versions.append(winreg.EnumKey(python_core, i))
                 i = i + 1
-            except WindowsError:
+            except OSError:
                 break
         exes = dict()
         for ver in versions:
             try:
                 path = winreg.QueryValue(python_core, "%s\\InstallPath" % ver)
-            except WindowsError:
+            except OSError:
                 continue
             exes[ver] = join(path, "python.exe")
 
@@ -171,7 +173,7 @@ if is_pypy:
     REQUIRED_MODULES.extend(['traceback', 'linecache'])
 
 
-class Logger(object):
+class Logger:
 
     """
     Logging object for use in command-line script.  Allows ranges of
@@ -433,7 +435,7 @@ class ConfigOptionParser(optparse.OptionParser):
     configuration files and environmental variables
     """
     def __init__(self, *args, **kwargs):
-        self.config = ConfigParser.RawConfigParser()
+        self.config = six.moves.configparser.RawConfigParser()
         self.files = self.get_config_files()
         self.config.read(self.files)
         optparse.OptionParser.__init__(self, *args, **kwargs)
@@ -479,7 +481,7 @@ class ConfigOptionParser(optparse.OptionParser):
                     val = option.convert_value(key, val)
                 except optparse.OptionValueError:
                     e = sys.exc_info()[1]
-                    print("An error occurred during configuration: %s" % e)
+                    print(("An error occurred during configuration: %s" % e))
                     sys.exit(3)
                 defaults[option.dest] = val
         return defaults
@@ -512,7 +514,7 @@ class ConfigOptionParser(optparse.OptionParser):
         defaults = self.update_defaults(self.defaults.copy())  # ours
         for option in self._get_all_options():
             default = defaults.get(option.dest)
-            if isinstance(default, basestring):
+            if isinstance(default, str):
                 opt_str = option.get_opt_string()
                 defaults[option.dest] = option.check_value(opt_str, default)
         return optparse.Values(defaults)
@@ -679,8 +681,8 @@ def main():
         parser.print_help()
         sys.exit(2)
     if len(args) > 1:
-        print('There must be only one argument: DEST_DIR (you gave %s)' % (
-            ' '.join(args)))
+        print(('There must be only one argument: DEST_DIR (you gave %s)' % (
+            ' '.join(args))))
         parser.print_help()
         sys.exit(2)
 
@@ -758,7 +760,7 @@ def call_subprocess(cmd, show_stdout=True,
     except Exception:
         e = sys.exc_info()[1]
         logger.fatal(
-            "Error %s while executing command %s" % (e, cmd_desc))
+            "Error {} while executing command {}".format(e, cmd_desc))
         raise
     all_output = []
     if stdout is not None:
@@ -831,7 +833,7 @@ def find_wheels(projects, search_dirs):
                 break
         else:
             # We're out of luck, so quit with a suitable error
-            logger.fatal('Cannot find a wheel for %s' % (project,))
+            logger.fatal('Cannot find a wheel for {}'.format(project))
 
     return wheels
 
@@ -846,8 +848,8 @@ def install_wheel(project_names, py_executable, search_dirs=None,
     # PIP_FIND_LINKS uses space as the path separator and thus cannot have paths
     # with spaces in them. Convert any of those to local file:// URL form.
     try:
-        from urlparse import urljoin
-        from urllib import pathname2url
+        from urllib.parse import urljoin
+        from urllib.request import pathname2url
     except ImportError:
         from urllib.parse import urljoin
         from urllib.request import pathname2url
@@ -974,12 +976,12 @@ def path_locations(home_dir):
             size = max(len(home_dir)+1, 256)
             buf = ctypes.create_unicode_buffer(size)
             try:
-                u = unicode
+                u = str
             except NameError:
                 u = str
             ret = GetShortPathName(u(home_dir), buf, size)
             if not ret:
-                print('Error: the path "%s" has a space in it' % home_dir)
+                print(('Error: the path "%s" has a space in it' % home_dir))
                 print('We could not determine the short pathname for it.')
                 print('Exiting.')
                 sys.exit(3)
@@ -1243,9 +1245,9 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
                 os.unlink(python_d_dest)
             # we need to copy the DLL to enforce that windows will load the correct one.
             # may not exist if we are cygwin.
-            py_executable_dll = 'python%s%s.dll' % (
+            py_executable_dll = 'python{}{}.dll'.format(
                 sys.version_info[0], sys.version_info[1])
-            py_executable_dll_d = 'python%s%s_d.dll' % (
+            py_executable_dll_d = 'python{}{}_d.dll'.format(
                 sys.version_info[0], sys.version_info[1])
             pythondll = os.path.join(os.path.dirname(sys.executable), py_executable_dll)
             pythondll_d = os.path.join(os.path.dirname(sys.executable), py_executable_dll_d)
@@ -1351,7 +1353,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
     if not is_win:
         # Ensure that 'python', 'pythonX' and 'pythonX.Y' all exist
         py_exe_version_major = 'python%s' % sys.version_info[0]
-        py_exe_version_major_minor = 'python%s.%s' % (
+        py_exe_version_major_minor = 'python{}.{}'.format(
             sys.version_info[0], sys.version_info[1])
         py_exe_no_version = 'python'
         required_symlinks = [ py_exe_no_version, py_exe_version_major,
@@ -1388,7 +1390,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
     except OSError:
         e = sys.exc_info()[1]
         if e.errno == errno.EACCES:
-            logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
+            logger.fatal('ERROR: The executable {} could not be run: {}'.format(py_executable, e))
             sys.exit(100)
         else:
             raise e
@@ -1529,7 +1531,7 @@ def fix_lib64(lib_dir, symlink=True):
         return
     # Check we have a lib64 library path
     if not [p for p in distutils.sysconfig.get_config_vars().values()
-            if isinstance(p, basestring) and 'lib64' in p]:
+            if isinstance(p, str) and 'lib64' in p]:
         return
 
     logger.debug('This system uses lib64; symlinking lib64 to lib')
@@ -1566,10 +1568,10 @@ def resolve_interpreter(exe):
                 exe = join(path, exe)
                 break
     if not os.path.exists(exe):
-        logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe))
+        logger.fatal('The executable {} (from --python={}) does not exist'.format(exe, exe))
         raise SystemExit(3)
     if not is_executable(exe):
-        logger.fatal('The executable %s (from --python=%s) is not executable' % (exe, exe))
+        logger.fatal('The executable {} (from --python={}) is not executable'.format(exe, exe))
         raise SystemExit(3)
     return exe
 
@@ -1703,7 +1705,7 @@ def fixup_pth_file(filename):
         else:
             new_value = make_relative_path(filename, line)
             if line != new_value:
-                logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename))
+                logger.debug('Rewriting path {} as {} (in {})'.format(line, new_value, filename))
             lines.append(new_value)
     if lines == prev_lines:
         logger.info('No changes to .pth file %s' % filename)
@@ -1719,7 +1721,7 @@ def fixup_egg_link(filename):
         logger.debug('Link in %s already relative' % filename)
         return
     new_link = make_relative_path(filename, link)
-    logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link))
+    logger.notify('Rewriting link {} in {} as {}'.format(link, filename, new_link))
     with open(filename, 'w') as f:
         f.write(new_link)
 
@@ -2200,7 +2202,7 @@ LC_LOAD_DYLIB = 0xc
 maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
 
 
-class fileview(object):
+class fileview:
     """
     A proxy for file-like objects that exposes a given view of a file.
     Modified from macholib.
@@ -2224,7 +2226,7 @@ class fileview(object):
 
     def _checkwindow(self, seekto, op):
         if not (self._start <= seekto <= self._end):
-            raise IOError("%s to offset %d is outside window [%d, %d]" % (
+            raise OSError("%s to offset %d is outside window [%d, %d]" % (
                 op, seekto, self._start, self._end))
 
     def seek(self, offset, whence=0):
@@ -2236,7 +2238,7 @@ class fileview(object):
         elif whence == os.SEEK_END:
             seekto += self._end
         else:
-            raise IOError("Invalid whence argument to seek: %r" % (whence,))
+            raise OSError("Invalid whence argument to seek: {!r}".format(whence))
         self._checkwindow(seekto, 'seek')
         self._fileobj.seek(seekto)
         self._pos = seekto - self._start
@@ -2300,7 +2302,7 @@ def mach_o_change(path, what, value):
                 # If the string is what is being replaced, overwrite it.
                 if load == what:
                     file.seek(where + name_offset, os.SEEK_SET)
-                    file.write(value.encode() + '\0'.encode())
+                    file.write(value.encode() + b'\0')
             # Seek to the next command
             file.seek(where + cmdsize, os.SEEK_SET)
 
diff --git a/python/virtualenv/virtualenv_embedded/distutils-init.py b/python/virtualenv/virtualenv_embedded/distutils-init.py
index 29fc1da459..fe392b712b 100644
--- a/python/virtualenv/virtualenv_embedded/distutils-init.py
+++ b/python/virtualenv/virtualenv_embedded/distutils-init.py
@@ -25,9 +25,9 @@ else:
 from distutils import dist, sysconfig
 
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 ## patch build_ext (distutils doesn't know how to get the libs directory
 ## path on windows - it hardcodes the paths around the patched sys.prefix)
@@ -38,7 +38,7 @@ if sys.platform == 'win32':
         def finalize_options (self):
             if self.library_dirs is None:
                 self.library_dirs = []
-            elif isinstance(self.library_dirs, basestring):
+            elif isinstance(self.library_dirs, str):
                 self.library_dirs = self.library_dirs.split(os.pathsep)
             
             self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
diff --git a/python/virtualenv/virtualenv_embedded/site.py b/python/virtualenv/virtualenv_embedded/site.py
index 7969769c36..abf7dce9ca 100644
--- a/python/virtualenv/virtualenv_embedded/site.py
+++ b/python/virtualenv/virtualenv_embedded/site.py
@@ -63,10 +63,11 @@ ImportError exception, it is silently ignored.
 
 """
 
+from __future__ import print_function
 import sys
 import os
 try:
-    import __builtin__ as builtins
+    import builtins as builtins
 except ImportError:
     import builtins
 try:
@@ -134,7 +135,7 @@ def addbuilddir():
     """Append ./build/lib.<platform> in case we're running in the build dir
     (especially for Guido :-)"""
     from distutils.util import get_platform
-    s = "build/lib.%s-%.3s" % (get_platform(), sys.version)
+    s = "build/lib.{}-{:.3}".format(get_platform(), sys.version)
     if hasattr(sys, 'gettotalrefcount'):
         s += '-pydebug'
     s = os.path.join(os.path.dirname(sys.path[-1]), s)
@@ -162,8 +163,8 @@ def addpackage(sitedir, name, known_paths):
         reset = 0
     fullname = os.path.join(sitedir, name)
     try:
-        f = open(fullname, "rU")
-    except IOError:
+        f = open(fullname)
+    except OSError:
         return
     try:
         for line in f:
@@ -196,7 +197,7 @@ def addsitedir(sitedir, known_paths=None):
         sys.path.append(sitedir)        # Add path component
     try:
         names = os.listdir(sitedir)
-    except os.error:
+    except OSError:
         return
     names.sort()
     for name in names:
@@ -388,11 +389,11 @@ def setquit():
     else:
         eof = 'Ctrl-D (i.e. EOF)'
 
-    class Quitter(object):
+    class Quitter:
         def __init__(self, name):
             self.name = name
         def __repr__(self):
-            return 'Use %s() or %s to exit' % (self.name, eof)
+            return 'Use {}() or {} to exit'.format(self.name, eof)
         def __call__(self, code=None):
             # Shells like IDLE catch the SystemExit, but listen when their
             # stdin wrapper is closed.
@@ -405,7 +406,7 @@ def setquit():
     builtins.exit = Quitter('exit')
 
 
-class _Printer(object):
+class _Printer:
     """interactive prompt objects for printing the license text, a list of
     contributors and the copyright notice."""
 
@@ -426,11 +427,11 @@ class _Printer(object):
             for filename in self.__files:
                 filename = os.path.join(dir, filename)
                 try:
-                    fp = open(filename, "rU")
+                    fp = open(filename)
                     data = fp.read()
                     fp.close()
                     break
-                except IOError:
+                except OSError:
                     pass
             if data:
                 break
@@ -453,7 +454,7 @@ class _Printer(object):
         while 1:
             try:
                 for i in range(lineno, lineno + self.MAXLINES):
-                    print(self.__lines[i])
+                    print((self.__lines[i]))
             except IndexError:
                 break
             else:
@@ -461,9 +462,9 @@ class _Printer(object):
                 key = None
                 while key is None:
                     try:
-                        key = raw_input(prompt)
-                    except NameError:
                         key = input(prompt)
+                    except NameError:
+                        key = eval(input(prompt))
                     if key not in ('', 'q'):
                         key = None
                 if key == 'q':
@@ -491,7 +492,7 @@ def setcopyright():
         [os.path.join(here, os.pardir), here, os.curdir])
 
 
-class _Helper(object):
+class _Helper:
     """Define the built-in 'help'.
     This is a wrapper around pydoc.help (with a twist).
 
@@ -721,16 +722,16 @@ def _script():
     if not args:
         print("sys.path = [")
         for dir in sys.path:
-            print("    %r," % (dir,))
+            print(("    {!r},".format(dir)))
         print("]")
         def exists(path):
             if os.path.isdir(path):
                 return "exists"
             else:
                 return "doesn't exist"
-        print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
-        print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
-        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        print(("USER_BASE: {!r} ({})".format(USER_BASE, exists(USER_BASE))))
+        print(("USER_SITE: {!r} ({})".format(USER_SITE, exists(USER_BASE))))
+        print(("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE))
         sys.exit(0)
 
     buffer = []
@@ -740,7 +741,7 @@ def _script():
         buffer.append(USER_SITE)
 
     if buffer:
-        print(os.pathsep.join(buffer))
+        print((os.pathsep.join(buffer)))
         if ENABLE_USER_SITE:
             sys.exit(0)
         elif ENABLE_USER_SITE is False:
@@ -751,7 +752,7 @@ def _script():
             sys.exit(3)
     else:
         import textwrap
-        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        print((textwrap.dedent(help % (sys.argv[0], os.pathsep))))
         sys.exit(10)
 
 if __name__ == '__main__':
diff --git a/python/voluptuous/setup.py b/python/voluptuous/setup.py
index 2fc07251dd..70d6cc23f8 100644
--- a/python/voluptuous/setup.py
+++ b/python/voluptuous/setup.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 try:
     from setuptools import setup
 except ImportError:
diff --git a/python/voluptuous/voluptuous.py b/python/voluptuous/voluptuous.py
index 132c3c476f..e7d0787b58 100644
--- a/python/voluptuous/voluptuous.py
+++ b/python/voluptuous/voluptuous.py
@@ -1,4 +1,3 @@
-# encoding: utf-8
 #
 # Copyright (C) 2010-2013 Alec Thomas <alec@swapoff.org>
 # All rights reserved.
@@ -93,17 +92,12 @@ from contextlib import contextmanager
 from functools import wraps
 
 
-if sys.version_info >= (3,):
-    import urllib.parse as urlparse
-    long = int
-    unicode = str
-    basestring = str
-    ifilter = filter
-    iteritems = lambda d: d.items()
-else:
-    from itertools import ifilter
-    import urlparse
-    iteritems = lambda d: d.iteritems()
+import urllib.parse as urlparse
+long = int
+str = str
+str = str
+ifilter = filter
+iteritems = lambda d: list(d.items())
 
 
 __author__ = 'Alec Thomas <alec@swapoff.org>'
@@ -116,12 +110,12 @@ def raises(exc, msg=None, regex=None):
         yield
     except exc as e:
         if msg is not None:
-            assert str(e) == msg, '%r != %r' % (str(e), msg)
+            assert str(e) == msg, '{!r} != {!r}'.format(str(e), msg)
         if regex is not None:
-            assert re.search(regex, str(e)), '%r does not match %r' % (str(e), regex)
+            assert re.search(regex, str(e)), '{!r} does not match {!r}'.format(str(e), regex)
 
 
-class Undefined(object):
+class Undefined:
     def __nonzero__(self):
         return False
 
@@ -310,7 +304,7 @@ class VirtualPathComponent(str):
         return self.__str__()
 
 
-class Schema(object):
+class Schema:
     """A validation schema.
 
     The schema is a Python tree-like structure where nodes are pattern
@@ -348,7 +342,7 @@ class Schema(object):
         self._compiled = self._compile(schema)
 
     def __repr__(self):
-        return "<Schema(%s, extra=%s, required=%s) object at 0x%x>" % (
+        return "<Schema({}, extra={}, required={}) object at 0x{:x}>".format(
             self.schema, self._extra_to_name.get(self.extra, '??'),
             self.required, id(self))
 
@@ -367,7 +361,7 @@ class Schema(object):
             return lambda _, v: v
         if isinstance(schema, Object):
             return self._compile_object(schema)
-        if isinstance(schema, collections.Mapping):
+        if isinstance(schema, collections.abc.Mapping):
             return self._compile_dict(schema)
         elif isinstance(schema, list):
             return self._compile_list(schema)
@@ -376,7 +370,7 @@ class Schema(object):
         type_ = type(schema)
         if type_ is type:
             type_ = schema
-        if type_ in (bool, int, long, str, unicode, float, complex, object,
+        if type_ in (bool, int, int, str, str, float, complex, object,
                      list, dict, type(None)) or callable(schema):
             return _compile_scalar(schema)
         raise SchemaError('unsupported schema data type %r' %
@@ -387,15 +381,15 @@ class Schema(object):
         invalid_msg = invalid_msg or 'mapping value'
 
         # Keys that may be required
-        all_required_keys = set(key for key in schema
+        all_required_keys = {key for key in schema
                                 if key is not Extra
                                 and ((self.required and not isinstance(key, (Optional, Remove)))
-                                     or isinstance(key, Required)))
+                                     or isinstance(key, Required))}
 
         # Keys that may have defaults
-        all_default_keys = set(key for key in schema
+        all_default_keys = {key for key in schema
                                if isinstance(key, Required)
-                               or isinstance(key, Optional))
+                               or isinstance(key, Optional)}
 
         _compiled_schema = {}
         for skey, svalue in iteritems(schema):
@@ -517,9 +511,9 @@ class Schema(object):
         def validate_object(path, data):
             if (schema.cls is not UNDEFINED
                     and not isinstance(data, schema.cls)):
-                raise ObjectInvalid('expected a {0!r}'.format(schema.cls), path)
+                raise ObjectInvalid('expected a {!r}'.format(schema.cls), path)
             iterable = _iterate_object(data)
-            iterable = ifilter(lambda item: item[1] is not None, iterable)
+            iterable = filter(lambda item: item[1] is not None, iterable)
             out = base_validate(path, iterable, {})
             return type(data)(**out)
 
@@ -864,8 +858,7 @@ def _iterate_object(obj):
         # maybe we have named tuple here?
         if hasattr(obj, '_asdict'):
             d = obj._asdict()
-    for item in iteritems(d):
-        yield item
+    yield from iteritems(d)
     try:
         slots = obj.__slots__
     except AttributeError:
@@ -882,10 +875,10 @@ class Object(dict):
 
     def __init__(self, schema, cls=UNDEFINED):
         self.cls = cls
-        super(Object, self).__init__(schema)
+        super().__init__(schema)
 
 
-class Marker(object):
+class Marker:
     """Mark nodes for special treatment."""
 
     def __init__(self, schema, msg=None):
@@ -934,7 +927,7 @@ class Optional(Marker):
     {'key2': 'value'}
     """
     def __init__(self, schema, msg=None, default=UNDEFINED):
-        super(Optional, self).__init__(schema, msg=msg)
+        super().__init__(schema, msg=msg)
         self.default = default_factory(default)
 
 
@@ -974,7 +967,7 @@ class Exclusive(Optional):
     ...             'social': {'social_network': 'barfoo', 'token': 'tEMp'}})
     """
     def __init__(self, schema, group_of_exclusion, msg=None):
-        super(Exclusive, self).__init__(schema, msg=msg)
+        super().__init__(schema, msg=msg)
         self.group_of_exclusion = group_of_exclusion
 
 
@@ -1021,7 +1014,7 @@ class Inclusive(Optional):
     """
 
     def __init__(self, schema, group_of_inclusion, msg=None):
-        super(Inclusive, self).__init__(schema, msg=msg)
+        super().__init__(schema, msg=msg)
         self.group_of_inclusion = group_of_inclusion
 
 
@@ -1040,7 +1033,7 @@ class Required(Marker):
     {'key': []}
     """
     def __init__(self, schema, msg=None, default=UNDEFINED):
-        super(Required, self).__init__(schema, msg=msg)
+        super().__init__(schema, msg=msg)
         self.default = default_factory(default)
 
 
@@ -1059,11 +1052,11 @@ class Remove(Marker):
     [1, 2, 3, 5, '7']
     """
     def __call__(self, v):
-        super(Remove, self).__call__(v)
+        super().__call__(v)
         return self.__class__
 
     def __repr__(self):
-        return "Remove(%r)" % (self.schema,)
+        return "Remove({!r})".format(self.schema)
 
 
 def Extra(_):
@@ -1075,7 +1068,7 @@ def Extra(_):
 # deprecated object, so we just leave an alias here instead.
 extra = Extra
 
-class Msg(object):
+class Msg:
     """Report a user-friendly message if a schema fails to validate.
 
     >>> validate = Schema(
@@ -1123,7 +1116,7 @@ class Msg(object):
                 raise (self.cls or Invalid)(self.msg)
 
     def __repr__(self):
-        return 'Msg(%s, %s, cls=%s)' % (self._schema, self.msg, self.cls)
+        return 'Msg({}, {}, cls={})'.format(self._schema, self.msg, self.cls)
 
 
 def message(default=None, cls=None):
@@ -1192,7 +1185,7 @@ def truth(f):
     return check
 
 
-class Coerce(object):
+class Coerce:
     """Coerce a value to a type.
 
     If the type constructor throws a ValueError or TypeError, the value
@@ -1226,7 +1219,7 @@ class Coerce(object):
             raise CoerceInvalid(msg)
 
     def __repr__(self):
-        return 'Coerce(%s, msg=%r)' % (self.type_name, self.msg)
+        return 'Coerce({}, msg={!r})'.format(self.type_name, self.msg)
 
 
 @message('value was not true', cls=TrueInvalid)
@@ -1299,7 +1292,7 @@ def Boolean(v):
     ... except MultipleInvalid as e:
     ...   assert isinstance(e.errors[0], BooleanInvalid)
     """
-    if isinstance(v, basestring):
+    if isinstance(v, str):
         v = v.lower()
         if v in ('1', 'true', 'yes', 'on', 'enable'):
             return True
@@ -1309,7 +1302,7 @@ def Boolean(v):
     return bool(v)
 
 
-class Any(object):
+class Any:
     """Use the first validated value.
 
     :param msg: Message to deliver to user if validation fails.
@@ -1360,7 +1353,7 @@ class Any(object):
 Or = Any
 
 
-class All(object):
+class All:
     """Value must pass all validators.
 
     The output of each validator is passed as input to the next.
@@ -1387,7 +1380,7 @@ class All(object):
         return v
 
     def __repr__(self):
-        return 'All(%s, msg=%r)' % (
+        return 'All({}, msg={!r})'.format(
             ", ".join(repr(v) for v in self.validators),
             self.msg
         )
@@ -1397,7 +1390,7 @@ class All(object):
 And = All
 
 
-class Match(object):
+class Match:
     """Value must be a string that matches the regular expression.
 
     >>> validate = Schema(Match(r'^0x[A-F0-9]+$'))
@@ -1417,7 +1410,7 @@ class Match(object):
     """
 
     def __init__(self, pattern, msg=None):
-        if isinstance(pattern, basestring):
+        if isinstance(pattern, str):
             pattern = re.compile(pattern)
         self.pattern = pattern
         self.msg = msg
@@ -1432,10 +1425,10 @@ class Match(object):
         return v
 
     def __repr__(self):
-        return 'Match(%r, msg=%r)' % (self.pattern.pattern, self.msg)
+        return 'Match({!r}, msg={!r})'.format(self.pattern.pattern, self.msg)
 
 
-class Replace(object):
+class Replace:
     """Regex substitution.
 
     >>> validate = Schema(All(Replace('you', 'I'),
@@ -1445,7 +1438,7 @@ class Replace(object):
     """
 
     def __init__(self, pattern, substitution, msg=None):
-        if isinstance(pattern, basestring):
+        if isinstance(pattern, str):
             pattern = re.compile(pattern)
         self.pattern = pattern
         self.substitution = substitution
@@ -1455,7 +1448,7 @@ class Replace(object):
         return self.pattern.sub(self.substitution, v)
 
     def __repr__(self):
-        return 'Replace(%r, %r, msg=%r)' % (self.pattern.pattern,
+        return 'Replace({!r}, {!r}, msg={!r})'.format(self.pattern.pattern,
                                             self.substitution,
                                             self.msg)
 
@@ -1540,7 +1533,7 @@ def PathExists(v):
     return os.path.exists(v)
 
 
-class Range(object):
+class Range:
     """Limit a value to a range.
 
     Either min or max may be omitted.
@@ -1596,7 +1589,7 @@ class Range(object):
                                                self.msg))
 
 
-class Clamp(object):
+class Clamp:
     """Clamp a value to a range.
 
     Either min or max may be omitted.
@@ -1622,14 +1615,14 @@ class Clamp(object):
         return v
 
     def __repr__(self):
-        return 'Clamp(min=%s, max=%s)' % (self.min, self.max)
+        return 'Clamp(min={}, max={})'.format(self.min, self.max)
 
 
 class LengthInvalid(Invalid):
     pass
 
 
-class Length(object):
+class Length:
     """The length of a value must be in a certain range."""
 
     def __init__(self, min=None, max=None, msg=None):
@@ -1647,14 +1640,14 @@ class Length(object):
         return v
 
     def __repr__(self):
-        return 'Length(min=%s, max=%s)' % (self.min, self.max)
+        return 'Length(min={}, max={})'.format(self.min, self.max)
 
 
 class DatetimeInvalid(Invalid):
     """The value is not a formatted datetime string."""
 
 
-class Datetime(object):
+class Datetime:
     """Validate that the value matches the datetime format."""
 
     DEFAULT_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
@@ -1680,7 +1673,7 @@ class InInvalid(Invalid):
     pass
 
 
-class In(object):
+class In:
     """Validate that a value is in a collection."""
 
     def __init__(self, container, msg=None):
@@ -1697,14 +1690,14 @@ class In(object):
         return v
 
     def __repr__(self):
-        return 'In(%s)' % (self.container,)
+        return 'In({})'.format(self.container)
 
 
 class NotInInvalid(Invalid):
     pass
 
 
-class NotIn(object):
+class NotIn:
     """Validate that a value is not in a collection."""
 
     def __init__(self, container, msg=None):
@@ -1721,7 +1714,7 @@ class NotIn(object):
         return v
 
     def __repr__(self):
-        return 'NotIn(%s)' % (self.container,)
+        return 'NotIn({})'.format(self.container)
 
 
 def Lower(v):
@@ -1774,7 +1767,7 @@ def Strip(v):
     return str(v).strip()
 
 
-class DefaultTo(object):
+class DefaultTo:
     """Sets a value to default_value if none provided.
 
     >>> s = Schema(DefaultTo(42))
@@ -1795,10 +1788,10 @@ class DefaultTo(object):
         return v
 
     def __repr__(self):
-        return 'DefaultTo(%s)' % (self.default_value(),)
+        return 'DefaultTo({})'.format(self.default_value())
 
 
-class SetTo(object):
+class SetTo:
     """Set a value, ignoring any previous value.
 
     >>> s = Schema(Any(int, SetTo(42)))
@@ -1815,14 +1808,14 @@ class SetTo(object):
         return self.value()
 
     def __repr__(self):
-        return 'SetTo(%s)' % (self.value(),)
+        return 'SetTo({})'.format(self.value())
 
 
 class ExactSequenceInvalid(Invalid):
     pass
 
 
-class ExactSequence(object):
+class ExactSequence:
     """Matches each element in a sequence against the corresponding element in
     the validators.
 
@@ -1857,14 +1850,14 @@ class ExactSequence(object):
                                                   for v in self.validators))
 
 
-class Literal(object):
+class Literal:
     def __init__(self, lit):
         self.lit = lit
 
     def __call__(self, value, msg=None):
         if self.lit != value:
             raise LiteralInvalid(
-                msg or '%s not match for %s' % (value, self.lit)
+                msg or '{} not match for {}'.format(value, self.lit)
             )
         else:
             return self.lit
@@ -1876,7 +1869,7 @@ class Literal(object):
         return repr(self.lit)
 
 
-class Unique(object):
+class Unique:
     """Ensure an iterable does not contain duplicate items.
 
     Only iterables convertable to a set are supported (native types and
@@ -1910,19 +1903,19 @@ class Unique(object):
             set_v = set(v)
         except TypeError as e:
             raise TypeInvalid(
-                self.msg or 'contains unhashable elements: {0}'.format(e))
+                self.msg or 'contains unhashable elements: {}'.format(e))
         if len(set_v) != len(v):
             seen = set()
-            dupes = list(set(x for x in v if x in seen or seen.add(x)))
+            dupes = list({x for x in v if x in seen or seen.add(x)})
             raise Invalid(
-                self.msg or 'contains duplicate items: {0}'.format(dupes))
+                self.msg or 'contains duplicate items: {}'.format(dupes))
         return v
 
     def __repr__(self):
         return 'Unique()'
 
 
-class Set(object):
+class Set:
     """Convert a list into a set.
 
     >>> s = Schema(Set())
@@ -1942,7 +1935,7 @@ class Set(object):
             set_v = set(v)
         except Exception as e:
             raise TypeInvalid(
-                self.msg or 'cannot be presented as set: {0}'.format(e))
+                self.msg or 'cannot be presented as set: {}'.format(e))
         return set_v
 
     def __repr__(self):
diff --git a/python/which/build.py b/python/which/build.py
index 3c8f09d39e..6f388c953b 100644
--- a/python/which/build.py
+++ b/python/which/build.py
@@ -22,6 +22,7 @@
     attributes).
 """
 
+from __future__ import print_function
 import os
 from os.path import basename, dirname, splitext, isfile, isdir, exists, \
                     join, abspath, normpath
@@ -129,7 +130,7 @@ def _run_in_dir(cmd, cwd, logstream=_RUN_DEFAULT_LOGSTREAM):
 def _rmtree_OnError(rmFunction, filePath, excInfo):
     if excInfo[0] == OSError:
         # presuming because file is read-only
-        os.chmod(filePath, 0777)
+        os.chmod(filePath, 0o777)
         rmFunction(filePath)
 def _rmtree(dirname):
     import shutil
@@ -192,12 +193,12 @@ def _listTargets(targets):
         nameWidth = max(nameWidth, len(name))
     nameWidth += 2  # space btwn name and doc
     format = "%%-%ds%%s" % nameWidth
-    print format % ("TARGET", "DESCRIPTION")
+    print((format % ("TARGET", "DESCRIPTION")))
     for name, func in sorted(targets.items()):
         doc = _first_paragraph(func.__doc__ or "", True)
         if len(doc) > (width - nameWidth):
             doc = doc[:(width-nameWidth-3)] + "..."
-        print format % (name, doc)
+        print((format % (name, doc)))
 
 
 # Recipe: first_paragraph (1.0.1) in /Users/trentm/tm/recipes/cookbook
@@ -234,7 +235,7 @@ def target_clean():
     ver = _get_project_version()
     dirs = ["dist", "build", "%s-%s" % (_project_name_, ver)]
     for d in dirs:
-        print "removing '%s'" % d
+        print(("removing '%s'" % d))
         if os.path.isdir(d): _rmtree(d)
 
     patterns = ["*.pyc", "*~", "MANIFEST",
@@ -243,7 +244,7 @@ def target_clean():
                ]
     for pattern in patterns:
         for file in glob.glob(pattern):
-            print "removing '%s'" % file
+            print(("removing '%s'" % file))
             os.unlink(file)
 
 
@@ -360,8 +361,8 @@ def target_upload():
 
     # Ensure have all the expected bits.
     expectedBits = [
-        re.compile("%s-.*\.zip$" % _project_name_),
-        re.compile("%s-.*\.web$" % _project_name_)
+        re.compile(r"%s-.*\.zip$" % _project_name_),
+        re.compile(r"%s-.*\.web$" % _project_name_)
     ]
     for expectedBit in expectedBits:
         for bit in bits:
@@ -409,13 +410,13 @@ def build(targets=[]):
     log.debug("build(targets=%r)" % targets)
     available = _getTargets()
     if not targets:
-        if available.has_key('default'):
+        if 'default' in available:
             return available['default']()
         else:   
             log.warn("No default target available. Doing nothing.")
     else:
         for target in targets:
-            if available.has_key(target):
+            if target in available:
                 retval = available[target]()
                 if retval:
                     raise Error("Error running '%s' target: retval=%s"\
diff --git a/python/which/test/test_which.py b/python/which/test/test_which.py
index b569769897..7698993b51 100644
--- a/python/which/test/test_which.py
+++ b/python/which/test/test_which.py
@@ -41,7 +41,7 @@ class WhichTestCase(unittest.TestCase):
         for app in self.testapps:
             path = os.path.join(self.tmpdir, app)
             open(path, 'wb').write('\n')
-            os.chmod(path, 0755)
+            os.chmod(path, 0o755)
 
     def tearDown(self):
         testsupport.rmtree(self.tmpdir)
@@ -66,7 +66,7 @@ class WhichTestCase(unittest.TestCase):
 
     def test_opt_version(self):
         output, error, retval = testsupport.run(self.which+' --version')
-        versionRe = re.compile("^which \d+\.\d+\.\d+$")
+        versionRe = re.compile(r"^which \d+\.\d+\.\d+$")
         versionMatch = versionRe.search(output.strip())
         self.failUnless(versionMatch,
                         "Version, '%s', from 'which --version' does not "\
diff --git a/python/which/test/testsupport.py b/python/which/test/testsupport.py
index 8ff519fada..2fdbd60e96 100644
--- a/python/which/test/testsupport.py
+++ b/python/which/test/testsupport.py
@@ -37,7 +37,7 @@ def run(argv):
     results.  Returns (<stdout lines>, <stderr lines>, <return value>).
     Note: 'argv' may also just be the command string.
     """
-    if type(argv) in (types.ListType, types.TupleType):
+    if type(argv) in (list, tuple):
         cmd = _joinArgv(argv)
     else:
         cmd = argv
@@ -73,7 +73,7 @@ def run(argv):
 def _rmtreeOnError(rmFunction, filePath, excInfo):
     if excInfo[0] == OSError:
         # presuming because file is read-only
-        os.chmod(filePath, 0777)
+        os.chmod(filePath, 0o777)
         rmFunction(filePath)
 
 def rmtree(dirname):
diff --git a/python/which/which.py b/python/which/which.py
index 8dd790518a..fec39731ec 100644
--- a/python/which/which.py
+++ b/python/which/which.py
@@ -33,6 +33,7 @@ of where the match was found. For example:
     from HKLM\SOFTWARE\...\perl.exe
 """
 
+from __future__ import print_function
 _cmdlnUsage = """
     Show the full path of commands.
 
@@ -90,13 +91,13 @@ def _getRegisteredExecutable(exeName):
     if sys.platform.startswith('win'):
         if os.path.splitext(exeName)[1].lower() != '.exe':
             exeName += '.exe'
-        import _winreg
+        import winreg
         try:
             key = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\" +\
                   exeName
-            value = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, key)
+            value = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, key)
             registered = (value, "from HKLM\\"+key)
-        except _winreg.error:
+        except winreg.error:
             pass
         if registered and not os.path.exists(registered[0]):
             registered = None
@@ -243,7 +244,7 @@ def which(command, path=None, verbose=0, exts=None):
     If no match is found for the command, a WhichError is raised.
     """
     try:
-        match = whichgen(command, path, verbose, exts).next()
+        match = next(whichgen(command, path, verbose, exts))
     except StopIteration:
         raise WhichError("Could not find '%s' on the path." % command)
     return match
@@ -280,17 +281,17 @@ def main(argv):
     try:
         optlist, args = getopt.getopt(argv[1:], 'haVvqp:e:',
             ['help', 'all', 'version', 'verbose', 'quiet', 'path=', 'exts='])
-    except getopt.GetoptError, msg:
+    except getopt.GetoptError as msg:
         sys.stderr.write("which: error: %s. Your invocation was: %s\n"\
                          % (msg, argv))
         sys.stderr.write("Try 'which --help'.\n")
         return 1
     for opt, optarg in optlist:
         if opt in ('-h', '--help'):
-            print _cmdlnUsage
+            print(_cmdlnUsage)
             return 0
         elif opt in ('-V', '--version'):
-            print "which %s" % __version__
+            print(("which %s" % __version__))
             return 0
         elif opt in ('-a', '--all'):
             all = 1
@@ -318,9 +319,9 @@ def main(argv):
         nmatches = 0
         for match in whichgen(arg, path=altpath, verbose=verbose, exts=exts):
             if verbose:
-                print "%s (%s)" % match
+                print(("%s (%s)" % match))
             else:
-                print match
+                print(match)
             nmatches += 1
             if not all:
                 break
diff --git a/security/generate_mapfile.py b/security/generate_mapfile.py
index 4479553bf8..289e176370 100644
--- a/security/generate_mapfile.py
+++ b/security/generate_mapfile.py
@@ -13,16 +13,17 @@
 # but the Mozilla build system is already running a Python script to generate
 # the file so it's simpler to just do the replacement in Python.
 
+from __future__ import print_function
 import buildconfig
 
 
 def main(output, input):
     if buildconfig.substs['OS_ARCH'] not in ('Linux', 'SunOS', 'Darwin', 'FreeBSD'):
-        print "Error: unhandled OS_ARCH %s" % buildconfig.substs['OS_ARCH']
+        print("Error: unhandled OS_ARCH %s" % buildconfig.substs['OS_ARCH'])
         return 1
     is_linux = buildconfig.substs['OS_ARCH'] in ('Linux', 'SunOS', 'FreeBSD')
 
-    with open(input, 'rb') as f:
+    with open(input, 'r') as f:
         for line in f:
             line = line.rstrip()
             # Remove all lines containing ';-'
diff --git a/security/manager/ssl/tests/unit/pycert.py b/security/manager/ssl/tests/unit/pycert.py
index 9c8efa915c..00e0f1a0dd 100755
--- a/security/manager/ssl/tests/unit/pycert.py
+++ b/security/manager/ssl/tests/unit/pycert.py
@@ -81,6 +81,7 @@ If a serial number is not explicitly specified, it is automatically
 generated based on the contents of the certificate.
 """
 
+from __future__ import print_function
 from pyasn1.codec.der import decoder
 from pyasn1.codec.der import encoder
 from pyasn1.type import constraint, namedtype, tag, univ, useful
@@ -694,4 +695,4 @@ def main(output, inputPath):
 # When run as a standalone program, this will read a specification from
 # stdin and output the certificate as PEM to stdout.
 if __name__ == '__main__':
-    print Certificate(sys.stdin).toPEM()
+    print(Certificate(sys.stdin).toPEM())
diff --git a/security/manager/ssl/tests/unit/pykey.py b/security/manager/ssl/tests/unit/pykey.py
index d3c43deb4c..eda89d53fd 100755
--- a/security/manager/ssl/tests/unit/pykey.py
+++ b/security/manager/ssl/tests/unit/pykey.py
@@ -30,6 +30,7 @@ secp384r1: an ECC key on the curve secp384r1
 secp521r1: an ECC key on the curve secp521r1
 """
 
+from __future__ import print_function
 from pyasn1.codec.der import encoder
 from pyasn1.type import univ, namedtype
 from pyasn1_modules import rfc2459
@@ -109,7 +110,7 @@ class RSAKey(object):
     # For reference, when encoded as a subject public key info, the
     # base64-encoded sha-256 hash of this key is
     # VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=
-    sharedRSA_N = long(
+    sharedRSA_N = int(
         '00ba8851a8448e16d641fd6eb6880636103d3c13d9eae4354ab4ecf56857'
         '6c247bc1c725a8e0d81fbdb19c069b6e1a86f26be2af5a756b6a6471087a'
         'a55aa74587f71cd5249c027ecd43fc1e69d038202993ab20c349e4dbb94c'
@@ -119,8 +120,8 @@ class RSAKey(object):
         '31a30c91ddb4caf7fcad1d25d309efb9170ea768e1b37b2f226f69e3b48a'
         '95611dee26d6259dab91084e36cb1c24042cbf168b2fe5f18f991731b8b3'
         'fe4923fa7251c431d503acda180a35ed8d', 16)
-    sharedRSA_E = 65537L
-    sharedRSA_D = long(
+    sharedRSA_E = 65537
+    sharedRSA_D = int(
         '009ecbce3861a454ecb1e0fe8f85dd43c92f5825ce2e997884d0e1a949da'
         'a2c5ac559b240450e5ac9fe0c3e31c0eefa6525a65f0c22194004ee1ab46'
         '3dde9ee82287cc93e746a91929c5e6ac3d88753f6c25ba5979e73e5d8fb2'
@@ -130,31 +131,31 @@ class RSAKey(object):
         '6cb9b5ebe64302041c78d908206b87009cb8cabacad3dbdb2792fb911b2c'
         'f4db6603585be9ae0ca3b8e6417aa04b06e470ea1a3b581ca03a6781c931'
         '5b62b30e6011f224725946eec57c6d9441', 16)
-    sharedRSA_P = long(
+    sharedRSA_P = int(
         '00dd6e1d4fffebf68d889c4d114cdaaa9caa63a59374286c8a5c29a717bb'
         'a60375644d5caa674c4b8bc7326358646220e4550d7608ac27d55b6db74f'
         '8d8127ef8fa09098b69147de065573447e183d22fe7d885aceb513d9581d'
         'd5e07c1a90f5ce0879de131371ecefc9ce72e9c43dc127d238190de81177'
         '3ca5d19301f48c742b', 16)
-    sharedRSA_Q = long(
+    sharedRSA_Q = int(
         '00d7a773d9ebc380a767d2fec0934ad4e8b5667240771acdebb5ad796f47'
         '8fec4d45985efbc9532968289c8d89102fadf21f34e2dd4940eba8c09d6d'
         '1f16dcc29729774c43275e9251ddbe4909e1fd3bf1e4bedf46a39b8b3833'
         '28ef4ae3b95b92f2070af26c9e7c5c9b587fedde05e8e7d86ca57886fb16'
         '5810a77b9845bc3127', 16)
-    sharedRSA_exp1 = long(
+    sharedRSA_exp1 = int(
         '0096472b41a610c0ade1af2266c1600e3671355ba42d4b5a0eb4e9d7eb35'
         '81400ba5dd132cdb1a5e9328c7bbc0bbb0155ea192972edf97d12751d8fc'
         'f6ae572a30b1ea309a8712dd4e33241db1ee455fc093f5bc9b592d756e66'
         '21474f32c07af22fb275d340792b32ba2590bbb261aefb95a258eea53765'
         '5315be9c24d191992d', 16)
-    sharedRSA_exp2 = long(
+    sharedRSA_exp2 = int(
         '28b450a7a75a856413b2bda6f7a63e3d964fb9ecf50e3823ef6cc8e8fa26'
         'ee413f8b9d1205540f12bbe7a0c76828b7ba65ad83cca4d0fe2a220114e1'
         'b35d03d5a85bfe2706bd50fce6cfcdd571b46ca621b8ed47d605bbe765b0'
         'aa4a0665ac25364da20154032e1204b8559d3e34fb5b177c9a56ff93510a'
         '5a4a6287c151de2d', 16)
-    sharedRSA_coef = long(
+    sharedRSA_coef = int(
         '28067b9355801d2ef52dfa96d8adb589673cf8ee8a9c6ff72aeeabe9ef6b'
         'e58a4f4abf05f788947dc851fdaa34542147a71a246bfb054ee76aa346ab'
         'cd2692cfc9e44c51e6f069c735e073ba019f6a7214961c91b26871caeabf'
@@ -164,7 +165,7 @@ class RSAKey(object):
     # For reference, when encoded as a subject public key info, the
     # base64-encoded sha-256 hash of this key is
     # MQj2tt1yGAfwFpWETYUCVrZxk2CD2705NKBQUlAaKJI=
-    alternateRSA_N = long(
+    alternateRSA_N = int(
         '00c175c65266099f77082a6791f1b876c37f5ce538b06c4acd22b1cbd46f'
         'a65ada2add41c8c2498ac4a3b3c1f61487f41b698941bd80a51c3c120244'
         'c584a4c4483305e5138c0106cf08be9a862760bae6a2e8f36f23c5d98313'
@@ -174,8 +175,8 @@ class RSAKey(object):
         'a69cd28375131f932b128ce286fa7d251c062ad27ef016f187cdd54e832b'
         '35b8930f74ba90aa8bc76167242ab1fd6d62140d18c4c0b8c68fc3748457'
         '324ad7de86e6552f1d1e191d712168d3bb', 16)
-    alternateRSA_E = 65537L
-    alternateRSA_D = long(
+    alternateRSA_E = 65537
+    alternateRSA_D = int(
         '7e3f6d7cb839ef66ae5d7dd92ff5410bb341dc14728d39034570e1a37079'
         '0f30f0681355fff41e2ad4e9a9d9fcebfbd127bdfab8c00affb1f3cea732'
         '7ead47aa1621f2ac1ee14ca02f04b3b2786017980b181a449d03b03e69d1'
@@ -185,38 +186,38 @@ class RSAKey(object):
         '857785269cd9d5bad2b57469e4afcd33c4ca2d2f699f11e7c8fbdcd484f0'
         '8d8efb8a3cb8a972eb24bed972efaae4bb712093e48fe94a46eb629a8750'
         '78c4021a9a2c93c9a70390e9d0a54401', 16)
-    alternateRSA_P = long(
+    alternateRSA_P = int(
         '00e63fc725a6ba76925a7ff8cb59c4f56dd7ec83fe85bf1f53e11cac9a81'
         '258bcfc0ae819077b0f2d1477aaf868de6a8ecbeaf7bb22b196f2a9ad82d'
         '3286f0d0cc29de719e5f2be8e509b7284d5963edd362f927887a4c4a8979'
         '9d340d51b301ac7601ab27179024fcaadd38bf6522af63eb16461ec02a7f'
         '27b06fe09ddda7c0a1', 16)
-    alternateRSA_Q = long(
+    alternateRSA_Q = int(
         '00d718b1fe9f8f99f00e832ae1fbdc6fe2ab27f34e049c498010fa0eb708'
         '4852182346083b5c96c3eee5592c014a410c6b930b165c13b5c26aa32eac'
         '6e7c925a8551c25134f2f4a72c6421f19a73148a0edfaba5d3a6888b35cb'
         'a18c00fd38ee5aaf0b545731d720761bbccdee744a52ca415e98e4de01cd'
         'fe764c1967b3e8cadb', 16)
-    alternateRSA_exp1 = long(
+    alternateRSA_exp1 = int(
         '01e5aca266c94a88d22e13c2b92ea247116c657a076817bdfd30db4b3a9d'
         '3095b9a4b6749647e2f84e7a784fc7838b08c85971cf7a036fa30e3b91c3'
         'c4d0df278f80c1b6e859d8456adb137defaa9f1f0ac5bac9a9184fd4ea27'
         '9d722ea626f160d78aad7bc83845ccb29df115c83f61b7622b99bd439c60'
         '9b5790a63c595181', 16)
-    alternateRSA_exp2 = long(
+    alternateRSA_exp2 = int(
         '0080cc45d10d2484ee0d1297fc07bf80b3beff461ea27e1f38f371789c3a'
         'f66b4a0edd2192c227791db4f1c77ae246bf342f31856b0f56581b58a95b'
         '1131c0c5396db2a8c3c6f39ea2e336bc205ae6a2a0b36869fca98cbba733'
         'cf01319a6f9bb26b7ca23d3017fc551cd8da8afdd17f6fa2e30d34868798'
         '1cd6234d571e90b7df', 16)
-    alternateRSA_coef = long(
+    alternateRSA_coef = int(
         '6f77c0c1f2ae7ac169561cca499c52bdfbe04cddccdbdc12aec5a85691e8'
         '594b7ee29908f30e7b96aa6254b80ed4aeec9b993782bdfc79b69d8d58c6'
         '8870fa4be1bc0c3527288c5c82bb4aebaf15edff110403fc78e6ace6a828'
         '27bf42f0cfa751e507651c5638db9393dd23dd1f6b295151de44b77fe55a'
         '7b0df271e19a65c0', 16)
 
-    evRSA_N = long(
+    evRSA_N = int(
         '00b549895c9d00108d11a1f99f87a9e3d1a5db5dfaecf188da57bf641368'
         '8f2ce4722cff109038c17402c93a2a473dbd286aed3fdcd363cf5a291477'
         '01bdd818d7615bf9356bd5d3c8336aaa8c0971368a06c3cd4461b93e5142'
@@ -226,8 +227,8 @@ class RSAKey(object):
         '1aae8aa2ccce348a0169b80e28a2d70c1a960c6f335f2da09b9b643f5abf'
         'ba49e8aaa981e960e27d87480bdd55dd9417fa18509fbb554ccf81a4397e'
         '8ba8128a34bdf27865c189e5734fb22905', 16)
-    evRSA_E = 65537L
-    evRSA_D = long(
+    evRSA_E = 65537
+    evRSA_D = int(
         '00983d54f94d6f4c76eb23d6f93d78523530cf73b0d16254c6e781768d45'
         'f55681d1d02fb2bd2aac6abc1c389860935c52a0d8f41482010394778314'
         '1d864bff30803638a5c0152570ae9d18f3d8ca163efb475b0dddf32e7e16'
@@ -237,38 +238,38 @@ class RSAKey(object):
         'fe274ae89431a10640be7899b0011c5e5093a1834708689de100634dabde'
         '60fbd6aaefa3a33df34a1f36f60c043036b748d1c9ee98c4031a0afec60e'
         'fda0a990be524f5614eac4fdb34a52f951', 16)
-    evRSA_P = long(
+    evRSA_P = int(
         '00eadc2cb33e5ff1ca376bbd95bd6a1777d2cf4fac47545e92d11a6209b9'
         'd5e4ded47834581c169b3c884742a09ea187505c1ca55414d8d25b497632'
         'd5ec2aaa05233430fad49892777a7d68e038f561a3b8969e60b0a263defb'
         'fda48a9b0ff39d95bc88b15267c8ade97b5107948e41e433249d87f7db10'
         '9d5d74584d86bcc1d7', 16)
-    evRSA_Q = long(
+    evRSA_Q = int(
         '00c59ae576a216470248d944a55b9e9bf93299da341ec56e558eba821abc'
         'e1bf57b79cf411d2904c774f9dba1f15185f607b0574a08205d6ec28b66a'
         '36d634232eaaf2fea37561abaf9d644b68db38c9964cb8c96ec0ac61eba6'
         '4d05b446542f423976f5acde4ecc95536d2df578954f93f0cfd9c58fb78b'
         'a2a76dd5ac284dc883', 16)
-    evRSA_exp1 = long(
+    evRSA_exp1 = int(
         '00c1d2ef3906331c52aca64811f9fe425beb2898322fb3db51032ce8d7e9'
         'fc32240be92019cf2480fcd5e329837127118b2a59a1bfe06c883e3a4447'
         'f3f031cd9aebd0b8d368fc79740d2cce8eadb324df7f091eafe1564361d5'
         '4920b01b0471230e5e47d93f8ed33963c517bc4fc78f6d8b1f9eba85bcce'
         'db7033026508db6285', 16)
-    evRSA_exp2 = long(
+    evRSA_exp2 = int(
         '008521b8db5694dfbe804a315f9efc9b65275c5490acf2a3456d65e6e610'
         'bf9f647fc67501d4f5772f232ac70ccdef9fc2a6dfa415c7c41b6afc7af9'
         'd07c3ca03f7ed93c09f0b99f2c304434322f1071709bbc1baa4c91575fa6'
         'a959e07d4996956d95e22b57938b6e47c8d51ffedfc9bf888ce0d1a3e42b'
         '65a89bed4b91d3e5f5', 16)
-    evRSA_coef = long(
+    evRSA_coef = int(
         '00dc497b06b920c8be0b0077b798e977eef744a90ec2c5d7e6cbb22448fa'
         'c72da81a33180e0d8a02e831460c7fc7fd3a612f7b9930b61b799f8e908e'
         '632e9ba0409b6aa70b03a3ba787426263b5bd5843df8476edb5d14f6a861'
         '3ebaf5b9cd5ca42f5fbd2802e08e4e49e5709f5151510caa5ab2c1c6eb3e'
         'fe9295d16e8c25c916', 16)
 
-    evRSA2040_N = long(
+    evRSA2040_N = int(
         '00ca7020dc215f57914d343fae4a015111697af997a5ece91866499fc23f'
         '1b88a118cbd30b10d91c7b9a0d4ee8972fcae56caf57f25fc1275a2a4dbc'
         'b982428c32ef587bf2387410330a0ffb16b8029bd783969ef675f6de38c1'
@@ -278,8 +279,8 @@ class RSAKey(object):
         '4748a3aa3e09e9eb4d461ea0027e540926614728b9d243975cf9a0541bef'
         'd25e76b51f951110b0e7644fc7e38441791b6d2227384cb8004e23342372'
         'b1cf5cc3e73e31b7bbefa160e6862ebb', 16)
-    evRSA2040_E = 65537L
-    evRSA2040_D = long(
+    evRSA2040_E = 65537
+    evRSA2040_D = int(
         '00b2db74bce92362abf72955a638ae8720ba3033bb7f971caf39188d7542'
         'eaa1c1abb5d205b1e2111f4791c08911a2e141e8cfd7054702d23100b564'
         '2c06e1a31b118afd1f9a2f396cced425c501d91435ca8656766ced2b93bb'
@@ -289,38 +290,38 @@ class RSAKey(object):
         'c7a8206fdae1c1d04bdbb1980d4a298c5a17dae4186474a5f7835d882bce'
         'f24aef4ed6f149f94d96c9f7d78e647fc778a9017ff208d3b4a1768b1821'
         '62102cdab032fabbab38d5200a324649', 16)
-    evRSA2040_P = long(
+    evRSA2040_P = int(
         '0f3844d0d4d4d6a21acd76a6fc370b8550e1d7ec5a6234172e790f0029ae'
         '651f6d5c59330ab19802b9d7a207de7a1fb778e3774fdbdc411750633d8d'
         '1b3fe075006ffcfd1d10e763c7a9227d2d5f0c2dade1c9e659c350a159d3'
         '6bb986f12636d4f9942b288bc0fe21da8799477173144249ca2e389e6c5c'
         '25aa78c8cad7d4df', 16)
-    evRSA2040_Q = long(
+    evRSA2040_Q = int(
         '0d4d0bedd1962f07a1ead6b23a4ed67aeaf1270f052a6d29ba074945c636'
         '1a5c4f8f07bf859e067aed3f4e6e323ef2aa8a6acd340b0bdc7cfe4fd329'
         'e3c97f870c7f7735792c6aa9d0f7e7542a28ed6f01b0e55a2b8d9c24a65c'
         '6da314c95484f5c7c3954a81bb016b07ed17ee9b06039695bca059a79f8d'
         'c2423d328d5265a5', 16)
-    evRSA2040_exp1 = long(
+    evRSA2040_exp1 = int(
         '09f29a2ff05be8a96d614ba31b08935420a86c6bc42b99a6692ea0da5763'
         'f01e596959b7ddce73ef9c2e4f6e5b40710887500d44ba0c3cd3132cba27'
         '475f39c2df7552e2d123a2497a4f97064028769a48a3624657f72bf539f3'
         'd0de234feccd3be8a0aa90c6bf6e9b0bed43070a24d061ff3ed1751a3ef2'
         'ff7f6b90b9dbd5fb', 16)
-    evRSA2040_exp2 = long(
+    evRSA2040_exp2 = int(
         '01a659e170cac120a03be1cf8f9df1caa353b03593bd7476e5853bd874c2'
         '87388601c6c341ce9d1d284a5eef1a3a669d32b816a5eaecd8b7844fe070'
         '64b9bca0c2b318d540277b3f7f1510d386bb36e03b04771e5d229e88893e'
         '13b753bfb94518bb638e2404bd6e6a993c1668d93fc0b82ff08aaf34347d'
         '3fe8397108c87ca5', 16)
-    evRSA2040_coef = long(
+    evRSA2040_coef = int(
         '040257c0d4a21c0b9843297c65652db66304fb263773d728b6abfa06d37a'
         'c0ca62c628023e09e37dc0a901e4ce1224180e2582a3aa4b6a1a7b98e2bd'
         '70077aec14ac8ab66a755c71e0fc102471f9bbc1b46a95aa0b645f2c38e7'
         '6450289619ea3f5e8ae61037bffcf8249f22aa4e76e2a01909f3feb290ce'
         '93edf57b10ebe796', 16)
 
-    rsa2040_N = long(
+    rsa2040_N = int(
         '00bac0652fdfbc0055882ffbaeaceec88fa2d083c297dd5d40664dd3d90f'
         '52f9aa02bd8a50fba16e0fd991878ef475f9b350d9f8e3eb2abd717ce327'
         'b09788531f13df8e3e4e3b9d616bb8a41e5306eed2472163161051180127'
@@ -330,8 +331,8 @@ class RSAKey(object):
         '4fa544607e53fc685c7a55fd44a81d4142b6af51ea6fa6cea52965a2e8c5'
         'd84f3ca024d6fbb9b005b9651ce5d9f2ecf40ed404981a9ffc02636e311b'
         '095c6332a0c87dc39271b5551481774b', 16)
-    rsa2040_E = 65537L
-    rsa2040_D = long(
+    rsa2040_E = 65537
+    rsa2040_D = int(
         '603db267df97555cbed86b8df355034af28f1eb7f3e7829d239bcc273a7c'
         '7a69a10be8f21f1b6c4b02c6bae3731c3158b5bbff4605f57ab7b7b2a0cb'
         'a2ec005a2db5b1ea6e0aceea5bc745dcd2d0e9d6b80d7eb0ea2bc08127bc'
@@ -341,101 +342,101 @@ class RSAKey(object):
         '1fedb80612529b39f59d0a3f8180b5ba201132197f93a5815ded938df8e7'
         'd93c9b15766588f339bb59100afda494a7e452d7dd4c9a19ce2ec3a33a18'
         'b20f0b4dade172bee19f26f0dcbe41', 16)
-    rsa2040_P = long(
+    rsa2040_P = int(
         '0ec3869cb92d406caddf7a319ab29448bc505a05913707873361fc5b986a'
         '499fb65eeb815a7e37687d19f128087289d9bb8818e7bcca502c4900ad9a'
         'ece1179be12ff3e467d606fc820ea8f07ac9ebffe2236e38168412028822'
         '3e42dbe68dfd972a85a6447e51695f234da7911c67c9ab9531f33df3b994'
         '32d4ee88c9a4efbb', 16)
-    rsa2040_Q = long(
+    rsa2040_Q = int(
         '0ca63934549e85feac8e0f5604303fd1849fe88af4b7f7e1213283bbc7a2'
         'c2a509f9273c428c68de3db93e6145f1b400bd6d4a262614e9043ad362d4'
         'eba4a6b995399c8934a399912199e841d8e8dbff0489f69e663796730b29'
         '80530b31cb70695a21625ea2adccc09d930516fa872211a91e22dd89fd9e'
         'b7da8574b72235b1', 16)
-    rsa2040_exp1 = long(
+    rsa2040_exp1 = int(
         '0d7d3a75e17f65f8a658a485c4095c10a4f66979e2b73bca9cf8ef21253e'
         '1facac6d4791f58392ce8656f88f1240cc90c29653e3100c6d7a38ed44b1'
         '63b339e5f3b6e38912126c69b3ceff2e5192426d9649b6ffca1abb75d2ba'
         '2ed6d9a26aa383c5973d56216ff2edb90ccf887742a0f183ac92c94cf187'
         '657645c7772d9ad7', 16)
-    rsa2040_exp2 = long(
+    rsa2040_exp2 = int(
         '03f550194c117f24bea285b209058032f42985ff55acebe88b16df9a3752'
         '7b4e61dc91a68dbc9a645134528ce5f248bda2893c96cb7be79ee73996c7'
         'c22577f6c2f790406f3472adb3b211b7e94494f32c5c6fcc0978839fe472'
         '4c31b06318a2489567b4fca0337acb1b841227aaa5f6c74800a2306929f0'
         '2ce038bad943df41', 16)
-    rsa2040_coef = long(
+    rsa2040_coef = int(
         '080a7dbfa8c2584814c71664c56eb62ce4caf16afe88d4499159d674774a'
         '3a3ecddf1256c02fc91525c527692422d0aba94e5c41ee12dc71bb66f867'
         '9fa17e096f28080851ba046eb31885c1414e8985ade599d907af17453d1c'
         'caea2c0d06443f8367a6be154b125e390ee0d90f746f08801dd3f5367f59'
         'fba2e5a67c05f375', 16)
 
-    rsa1024_N = long(
+    rsa1024_N = int(
         '00d3a97440101eba8c5df9503e6f935eb52ffeb3ebe9d0dc5cace26f973c'
         'a94cbc0d9c31d66c0c013bce9c82d0d480328df05fb6bcd7990a5312ddae'
         '6152ad6ee61c8c1bdd8663c68bd36224a9882ae78e89f556dfdbe6f51da6'
         '112cbfc27c8a49336b41afdb75321b52b24a7344d1348e646351a551c757'
         '1ccda0b8fe35f61a75', 16)
-    rsa1024_E = 65537L
-    rsa1024_D = long(
+    rsa1024_E = 65537
+    rsa1024_D = int(
         '5b6708e185548fc07ff062dba3792363e106ff9177d60ee3227162391024'
         '1813f958a318f26db8b6a801646863ebbc69190d6c2f5e7723433e99666d'
         '76b3987892cd568f1f18451e8dc05477c0607ee348380ebb7f4c98d0c036'
         'a0260bc67b2dab46cbaa4ce87636d839d8fddcbae2da3e02e8009a21225d'
         'd7e47aff2f82699d', 16)
-    rsa1024_P = long(
+    rsa1024_P = int(
         '00fcdee570323e8fc399dbfc63d8c1569546fb3cd6886c628668ab1e1d0f'
         'ca71058febdf76d702970ad6579d80ac2f9521075e40ef8f3f39983bd819'
         '07e898bad3', 16)
-    rsa1024_Q = long(
+    rsa1024_Q = int(
         '00d64801c955b4eb75fbae230faa8b28c9cc5e258be63747ff5ac8d2af25'
         '3e9f6d6ce03ea2eb13ae0eb32572feb848c32ca00743635374338fedacd8'
         'c5885f7897', 16)
-    rsa1024_exp1 = long(
+    rsa1024_exp1 = int(
         '76c0526d5b1b28368a75d5d42a01b9a086e20b9310241e2cd2d0b166a278'
         'c694ff1e9d25d9193d47789b52bb0fa194de1af0b77c09007f12afdfeef9'
         '58d108c3', 16)
-    rsa1024_exp2 = long(
+    rsa1024_exp2 = int(
         '008a41898d8b14217c4d782cbd15ef95d0a660f45ed09a4884f4e170367b'
         '946d2f20398b907896890e88fe17b54bd7febe133ebc7720c86fe0649cca'
         '7ca121e05f', 16)
-    rsa1024_coef = long(
+    rsa1024_coef = int(
         '22db133445f7442ea2a0f582031ee214ff5f661972986f172651d8d6b4ec'
         '3163e99bff1c82fe58ec3d075c6d8f26f277020edb77c3ba821b9ba3ae18'
         'ff8cb2cb', 16)
 
-    rsa1016_N = long(
+    rsa1016_N = int(
         '00d29bb12fb84fddcd29b3a519cb66c43b8d8f8be545ba79384ce663ed03'
         'df75991600eb920790d2530cece544db99a71f05896a3ed207165534aa99'
         '057e47c47e3bc81ada6fa1e12e37268b5046a55268f9dad7ccb485d81a2e'
         '19d50d4f0b6854acaf6d7be69d9a083136e15afa8f53c1c8c84fc6077279'
         'dd0e55d7369a5bdd', 16)
-    rsa1016_E = 65537L
-    rsa1016_D = long(
+    rsa1016_E = 65537
+    rsa1016_D = int(
         '3c4965070bf390c251d5a2c5277c5b5fd0bdee85cad7fe2b27982bb28511'
         '4a507004036ae1cf8ae54b25e4db39215abd7e903f618c2d8b2f08cc6cd1'
         '2dbccd72205e4945b6b3df389e5e43de0a148bb2c84e2431fdbe5920b044'
         'bb272f45ecff0721b7dfb60397fc613a9ea35c22300530cae8f9159c534d'
         'f3bf0910951901', 16)
-    rsa1016_P = long(
+    rsa1016_P = int(
         '0f9f17597c85b8051b9c69afb55ef576c996dbd09047d0ccde5b9d60ea5c'
         '67fe4fac67be803f4b6ac5a3f050f76b966fb14f5cf105761e5ade6dd960'
         'b183ba55', 16)
-    rsa1016_Q = long(
+    rsa1016_Q = int(
         '0d7b637112ce61a55168c0f9c9386fb279ab40cba0d549336bba65277263'
         'aac782611a2c81d9b635cf78c40018859e018c5e9006d12e3d2ee6f346e7'
         '9fa43369', 16)
-    rsa1016_exp1 = long(
+    rsa1016_exp1 = int(
         '09fd6c9a3ea6e91ae32070f9fc1c210ff9352f97be5d1eeb951bb39681e9'
         'dc5b672a532221b3d8900c9a9d99b9d0a4e102dc450ca1b87b0b1389de65'
         '16c0ae0d', 16)
-    rsa1016_exp2 = long(
+    rsa1016_exp2 = int(
         '0141b832491b7dd4a83308920024c79cae64bd447df883bb4c5672a96bab'
         '48b7123b34f26324452cdceb17f21e570e347cbe2fd4c2d8f9910eac2cb6'
         'd895b8c9', 16)
-    rsa1016_coef = long(
+    rsa1016_coef = int(
         '0458dd6aee18c88b2f9b81f1bc3075ae20dc1f9973d20724f20b06043d61'
         '47c8789d4a07ae88bc82c8438c893e017b13947f62e0b18958a31eb664b1'
         '9e64d3e0', 16)
@@ -575,11 +576,11 @@ secp521r1 = univ.ObjectIdentifier('1.3.132.0.35')
 # The third number is the parameter b of the definition of the curve
 #   E: y^2 = x^3 + ax + b (a in this case is 0)
 # The fourth and fifth numbers constitute the base point G.
-secp256k1Params = (long('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
-                   long('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16),
+secp256k1Params = (int('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
+                   int('fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16),
                    7,
-                   long('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16),
-                   long('483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 16))
+                   int('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798', 16),
+                   int('483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8', 16))
 
 def longToEvenLengthHexString(val):
     h = format(val, 'x')
@@ -703,4 +704,4 @@ def main(output, inputPath):
 # When run as a standalone program, this will read a specification from
 # stdin and output the certificate as PEM to stdout.
 if __name__ == '__main__':
-    print keyFromSpecification(sys.stdin.read()).toPEM()
+    print(keyFromSpecification(sys.stdin.read()).toPEM())
diff --git a/security/manager/ssl/tests/unit/test_cert_version/generate.py b/security/manager/ssl/tests/unit/test_cert_version/generate.py
index b99cbefe2c..39f69f7a07 100755
--- a/security/manager/ssl/tests/unit/test_cert_version/generate.py
+++ b/security/manager/ssl/tests/unit/test_cert_version/generate.py
@@ -58,10 +58,10 @@ basicConstraintsCA = 'extension:basicConstraints:cA,'
 
 writeCertspec('ca', 'ca', [keyUsage, basicConstraintsCA])
 
-for versionStr, versionVal in versions.iteritems():
+for versionStr, versionVal in versions.items():
     # intermediates
     versionText = 'version:%s' % versionVal
-    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.items():
         intermediateName = 'int-%s-%s' % (versionStr, basicConstraintsType)
         writeCertspec('ca', intermediateName,
                       [keyUsage, versionText, basicConstraintsExtension])
@@ -69,13 +69,13 @@ for versionStr, versionVal in versions.iteritems():
 
     # end-entities
     versionText = 'version:%s' % versionVal
-    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.items():
         writeCertspec('ca', 'ee-%s-%s' % (versionStr, basicConstraintsType),
                       [versionText, basicConstraintsExtension])
 
     # self-signed certificates
     versionText = 'version:%s' % versionVal
-    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
+    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.items():
         selfSignedName = 'ss-%s-%s' % (versionStr, basicConstraintsType)
         writeCertspec(selfSignedName, selfSignedName,
                       [versionText, basicConstraintsExtension])
diff --git a/security/manager/ssl/tests/unit/test_content_signing/pysign.py b/security/manager/ssl/tests/unit/test_content_signing/pysign.py
index c68c45b52d..3593b15d18 100644
--- a/security/manager/ssl/tests/unit/test_content_signing/pysign.py
+++ b/security/manager/ssl/tests/unit/test_content_signing/pysign.py
@@ -15,6 +15,7 @@ You can use pysign.py like this:
 cat test.txt | python pysign.py > test.txt.signature
 """
 
+from __future__ import print_function
 import base64
 import binascii
 import ecc
@@ -26,4 +27,4 @@ data = stdin.read()
 
 key = ecc.Key.Key.decode(binascii.unhexlify(pykey.ECCKey.secp384r1Encoded))
 sig = key.sign("Content-Signature:\00" + data, 'sha384')
-print base64.b64encode(sig).replace('+', '-').replace('/', '_')
+print(base64.b64encode(sig).replace('+', '-').replace('/', '_'))
diff --git a/security/nss/automation/release/nss-release-helper.py b/security/nss/automation/release/nss-release-helper.py
index 9e6ab9868b..8fdfe10b10 100644
--- a/security/nss/automation/release/nss-release-helper.py
+++ b/security/nss/automation/release/nss-release-helper.py
@@ -3,6 +3,7 @@
 # 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 print_function
 import os
 import sys
 import shutil
@@ -34,12 +35,12 @@ abi_report_files = ['automation/abi-check/expected-report-libfreebl3.so.txt',
 
 
 def check_call_noisy(cmd, *args, **kwargs):
-    print("Executing command: {}".format(cmd))
+    print(("Executing command: {}".format(cmd)))
     check_call(cmd, *args, **kwargs)
 
 
 def exit_with_failure(what):
-    print("failure: {}".format(what))
+    print(("failure: {}".format(what)))
     sys.exit(2)
 
 
@@ -229,7 +230,7 @@ def set_all_lib_versions(version, major, minor, patch, build):
         print("You're increasing the minor (or major) version:")
         print("- erasing ABI comparison expectations")
         new_branch = "NSS_" + str(old_major) + "_" + str(old_minor) + "_BRANCH"
-        print("- setting reference branch to the branch of the previous version: " + new_branch)
+        print(("- setting reference branch to the branch of the previous version: " + new_branch))
         with open(abi_base_version_file, "w") as abi_base:
             abi_base.write("%s\n" % new_branch)
         for report_file in abi_report_files:
@@ -303,7 +304,7 @@ def create_nss_release_archive():
     check_call_noisy(["hg", "archive", "-r", nssreltag, "--prefix=nss-" + nssrel + "/nss",
                       stagedir + "/" + nssreltag + "/src/" + nss_tar, "-X", ".hgtags"])
     check_call_noisy(["tar", "-xz", "-C", nss_stagedir, "-f", nsprtar_with_path])
-    print("changing to directory " + nss_stagedir)
+    print(("changing to directory " + nss_stagedir))
     os.chdir(nss_stagedir)
     check_call_noisy(["tar", "-xz", "-f", nss_tar])
     check_call_noisy(["mv", "-i", "nspr-" + nsprrel + "/nspr", "nss-" + nssrel + "/"])
@@ -314,7 +315,7 @@ def create_nss_release_archive():
     check_call_noisy(["tar", "-cz", "--remove-files", "-f", nss_nspr_tar, "nss-" + nssrel])
     check_call("sha1sum " + nss_tar + " " + nss_nspr_tar + " > SHA1SUMS", shell=True)
     check_call("sha256sum " + nss_tar + " " + nss_nspr_tar + " > SHA256SUMS", shell=True)
-    print("created directory " + nss_stagedir + " with files:")
+    print(("created directory " + nss_stagedir + " with files:"))
     check_call_noisy(["ls", "-l"])
 
 
diff --git a/security/nss/coreconf/check_cc.py b/security/nss/coreconf/check_cc.py
index d0736af7d6..ab48480a67 100644
--- a/security/nss/coreconf/check_cc.py
+++ b/security/nss/coreconf/check_cc.py
@@ -1,12 +1,13 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os
 import subprocess
 import sys
 
 def main():
     if sys.platform == 'win32' or len(sys.argv) < 2:
-        print(0)
+        print((0))
     else:
         cc = os.environ.get('CC', 'cc')
         try:
@@ -20,7 +21,7 @@ def main():
         except OSError:
             # We probably just don't have CC/cc.
             cc_is_arg = False
-        print(int(cc_is_arg))
+        print((int(cc_is_arg)))
 
 if __name__ == '__main__':
     main()
diff --git a/security/nss/coreconf/werror.py b/security/nss/coreconf/werror.py
index 2f622c5e11..6fa3367165 100644
--- a/security/nss/coreconf/werror.py
+++ b/security/nss/coreconf/werror.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os
 import subprocess
 
@@ -43,7 +44,7 @@ def main():
 
     def set_warning(warning, contra=''):
         if warning_supported(warning):
-            print('-W%s%s' % (contra, warning))
+            print(('-W%s%s' % (contra, warning)))
 
     if cc_is_clang:
         # clang is unable to handle glib's expansion of strcmp and similar for
diff --git a/security/nss/gtests/google_test/gtest/scripts/fuse_gtest_files.py b/security/nss/gtests/google_test/gtest/scripts/fuse_gtest_files.py
index d0dd464fe8..f89ec05b01 100755
--- a/security/nss/gtests/google_test/gtest/scripts/fuse_gtest_files.py
+++ b/security/nss/gtests/google_test/gtest/scripts/fuse_gtest_files.py
@@ -56,6 +56,7 @@ https://github.com/google/googletest/blob/master/googletest/docs/advanced.md for
 more information.
 """
 
+from __future__ import print_function
 __author__ = 'wan@google.com (Zhanyong Wan)'
 
 import os
@@ -93,8 +94,8 @@ def VerifyFileExists(directory, relative_path):
   """
 
   if not os.path.isfile(os.path.join(directory, relative_path)):
-    print('ERROR: Cannot find %s in directory %s.' % (relative_path,
-                                                      directory))
+    print(('ERROR: Cannot find %s in directory %s.' % (relative_path,
+                                                      directory)))
     print('Please either specify a valid project root directory '
           'or omit it on the command line.')
     sys.exit(1)
@@ -122,8 +123,8 @@ def VerifyOutputFile(output_dir, relative_path):
     # TODO(wan@google.com): The following user-interaction doesn't
     # work with automated processes.  We should provide a way for the
     # Makefile to force overwriting the files.
-    print('%s already exists in directory %s - overwrite it? (y/N) ' %
-          (relative_path, output_dir))
+    print(('%s already exists in directory %s - overwrite it? (y/N) ' %
+          (relative_path, output_dir)))
     answer = sys.stdin.readline().strip()
     if answer not in ['y', 'Y']:
       print('ABORTED.')
diff --git a/security/nss/gtests/google_test/gtest/scripts/gen_gtest_pred_impl.py b/security/nss/gtests/google_test/gtest/scripts/gen_gtest_pred_impl.py
index e09a6e0177..533ce60816 100755
--- a/security/nss/gtests/google_test/gtest/scripts/gen_gtest_pred_impl.py
+++ b/security/nss/gtests/google_test/gtest/scripts/gen_gtest_pred_impl.py
@@ -46,6 +46,7 @@ directory where the script is.  It also generates the accompanying
 unit test in file gtest_pred_impl_unittest.cc.
 """
 
+from __future__ import print_function
 __author__ = 'wan@google.com (Zhanyong Wan)'
 
 import os
@@ -184,7 +185,7 @@ def Title(word):
 def OneTo(n):
   """Returns the list [1, 2, 3, ..., n]."""
 
-  return range(1, n + 1)
+  return list(range(1, n + 1))
 
 
 def Iter(n, format, sep=''):
@@ -308,12 +309,12 @@ def GenerateFile(path, content):
   """Given a file path and a content string
      overwrites it with the given content.
   """
-  print 'Updating file %s . . .' % path
-  f = file(path, 'w+')
-  print >>f, content,
+  print('Updating file %s . . .' % path)
+  f = open(path, 'w+')
+  print(content, end=' ', file=f)
   f.close()
 
-  print 'File %s has been updated.' % path
+  print('File %s has been updated.' % path)
 
 
 def GenerateHeader(n):
@@ -720,8 +721,8 @@ def _Main():
   unit test."""
 
   if len(sys.argv) != 2:
-    print __doc__
-    print 'Author: ' + __author__
+    print(__doc__)
+    print('Author: ' + __author__)
     sys.exit(1)
 
   n = int(sys.argv[1])
diff --git a/security/nss/gtests/google_test/gtest/scripts/release_docs.py b/security/nss/gtests/google_test/gtest/scripts/release_docs.py
index 8d24f28fdf..2ab6bbbf34 100755
--- a/security/nss/gtests/google_test/gtest/scripts/release_docs.py
+++ b/security/nss/gtests/google_test/gtest/scripts/release_docs.py
@@ -61,6 +61,7 @@ EXAMPLE
        $ svn commit -m "release wiki pages for v2.6"
 """
 
+from __future__ import print_function
 __author__ = 'wan@google.com (Zhanyong Wan)'
 
 import os
@@ -127,11 +128,11 @@ class WikiBrancher(object):
   def BranchFiles(self):
     """Branches the .wiki files needed to be branched."""
 
-    print 'Branching %d .wiki files:' % (len(self.files_to_branch),)
+    print('Branching %d .wiki files:' % (len(self.files_to_branch),))
     os.chdir(self.wiki_dir)
     for f in self.files_to_branch:
       command = 'svn cp %s %s%s' % (f, self.version_prefix, f)
-      print command
+      print(command)
       os.system(command)
 
   def UpdateLinksInBranchedFiles(self):
@@ -139,10 +140,10 @@ class WikiBrancher(object):
     for f in self.files_to_branch:
       source_file = os.path.join(self.wiki_dir, f)
       versioned_file = os.path.join(self.wiki_dir, self.version_prefix + f)
-      print 'Updating links in %s.' % (versioned_file,)
-      text = file(source_file, 'r').read()
+      print('Updating links in %s.' % (versioned_file,))
+      text = open(source_file, 'r').read()
       new_text = self.search_for_re.sub(self.replace_with, text)
-      file(versioned_file, 'w').write(new_text)
+      open(versioned_file, 'w').write(new_text)
 
 
 def main():
diff --git a/security/nss/gtests/google_test/gtest/scripts/upload.py b/security/nss/gtests/google_test/gtest/scripts/upload.py
index eba571142f..c1df773b09 100755
--- a/security/nss/gtests/google_test/gtest/scripts/upload.py
+++ b/security/nss/gtests/google_test/gtest/scripts/upload.py
@@ -46,7 +46,8 @@ against by using the '--rev' option.
 # This code is derived from appcfg.py in the App Engine SDK (open source),
 # and from ASPN recipe #146306.
 
-import cookielib
+from __future__ import print_function
+import six.moves.http_cookiejar
 import getpass
 import logging
 import md5
@@ -57,9 +58,10 @@ import re
 import socket
 import subprocess
 import sys
-import urllib
-import urllib2
-import urlparse
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.parse
+import six
 
 try:
   import readline
@@ -94,15 +96,15 @@ def GetEmail(prompt):
       last_email = last_email_file.readline().strip("\n")
       last_email_file.close()
       prompt += " [%s]" % last_email
-    except IOError, e:
+    except IOError as e:
       pass
-  email = raw_input(prompt + ": ").strip()
+  email = input(prompt + ": ").strip()
   if email:
     try:
       last_email_file = open(last_email_file_name, "w")
       last_email_file.write(email)
       last_email_file.close()
-    except IOError, e:
+    except IOError as e:
       pass
   else:
     email = last_email
@@ -118,20 +120,20 @@ def StatusUpdate(msg):
     msg: The string to print.
   """
   if verbosity > 0:
-    print msg
+    print(msg)
 
 
 def ErrorExit(msg):
   """Print an error message to stderr and exit."""
-  print >>sys.stderr, msg
+  print(msg, file=sys.stderr)
   sys.exit(1)
 
 
-class ClientLoginError(urllib2.HTTPError):
+class ClientLoginError(six.moves.urllib.error.HTTPError):
   """Raised to indicate there was an error authenticating with ClientLogin."""
 
   def __init__(self, url, code, msg, headers, args):
-    urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
+    six.moves.urllib.error.HTTPError.__init__(self, url, code, msg, headers, None)
     self.args = args
     self.reason = args["Error"]
 
@@ -177,10 +179,10 @@ class AbstractRpcServer(object):
   def _CreateRequest(self, url, data=None):
     """Creates a new urllib request."""
     logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
-    req = urllib2.Request(url, data=data)
+    req = six.moves.urllib.request.Request(url, data=data)
     if self.host_override:
       req.add_header("Host", self.host_override)
-    for key, value in self.extra_headers.iteritems():
+    for key, value in self.extra_headers.items():
       req.add_header(key, value)
     return req
 
@@ -204,7 +206,7 @@ class AbstractRpcServer(object):
       account_type = "HOSTED"
     req = self._CreateRequest(
         url="https://www.google.com/accounts/ClientLogin",
-        data=urllib.urlencode({
+        data=six.moves.urllib.parse.urlencode({
             "Email": email,
             "Passwd": password,
             "service": "ah",
@@ -218,7 +220,7 @@ class AbstractRpcServer(object):
       response_dict = dict(x.split("=")
                            for x in response_body.split("\n") if x)
       return response_dict["Auth"]
-    except urllib2.HTTPError, e:
+    except six.moves.urllib.error.HTTPError as e:
       if e.code == 403:
         body = e.read()
         response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
@@ -240,14 +242,14 @@ class AbstractRpcServer(object):
     continue_location = "http://localhost/"
     args = {"continue": continue_location, "auth": auth_token}
     req = self._CreateRequest("http://%s/_ah/login?%s" %
-                              (self.host, urllib.urlencode(args)))
+                              (self.host, six.moves.urllib.parse.urlencode(args)))
     try:
       response = self.opener.open(req)
-    except urllib2.HTTPError, e:
+    except six.moves.urllib.error.HTTPError as e:
       response = e
     if (response.code != 302 or
         response.info()["location"] != continue_location):
-      raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
+      raise six.moves.urllib.error.HTTPError(req.get_full_url(), response.code, response.msg,
                               response.headers, response.fp)
     self.authenticated = True
 
@@ -270,34 +272,34 @@ class AbstractRpcServer(object):
       credentials = self.auth_function()
       try:
         auth_token = self._GetAuthToken(credentials[0], credentials[1])
-      except ClientLoginError, e:
+      except ClientLoginError as e:
         if e.reason == "BadAuthentication":
-          print >>sys.stderr, "Invalid username or password."
+          print("Invalid username or password.", file=sys.stderr)
           continue
         if e.reason == "CaptchaRequired":
-          print >>sys.stderr, (
+          print((
               "Please go to\n"
               "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
-              "and verify you are a human.  Then try again.")
+              "and verify you are a human.  Then try again."), file=sys.stderr)
           break
         if e.reason == "NotVerified":
-          print >>sys.stderr, "Account not verified."
+          print("Account not verified.", file=sys.stderr)
           break
         if e.reason == "TermsNotAgreed":
-          print >>sys.stderr, "User has not agreed to TOS."
+          print("User has not agreed to TOS.", file=sys.stderr)
           break
         if e.reason == "AccountDeleted":
-          print >>sys.stderr, "The user account has been deleted."
+          print("The user account has been deleted.", file=sys.stderr)
           break
         if e.reason == "AccountDisabled":
-          print >>sys.stderr, "The user account has been disabled."
+          print("The user account has been disabled.", file=sys.stderr)
           break
         if e.reason == "ServiceDisabled":
-          print >>sys.stderr, ("The user's access to the service has been "
-                               "disabled.")
+          print(("The user's access to the service has been "
+                               "disabled."), file=sys.stderr)
           break
         if e.reason == "ServiceUnavailable":
-          print >>sys.stderr, "The service is not available; try again later."
+          print("The service is not available; try again later.", file=sys.stderr)
           break
         raise
       self._GetAuthCookie(auth_token)
@@ -334,7 +336,7 @@ class AbstractRpcServer(object):
         args = dict(kwargs)
         url = "http://%s%s" % (self.host, request_path)
         if args:
-          url += "?" + urllib.urlencode(args)
+          url += "?" + six.moves.urllib.parse.urlencode(args)
         req = self._CreateRequest(url=url, data=payload)
         req.add_header("Content-Type", content_type)
         try:
@@ -342,7 +344,7 @@ class AbstractRpcServer(object):
           response = f.read()
           f.close()
           return response
-        except urllib2.HTTPError, e:
+        except six.moves.urllib.error.HTTPError as e:
           if tries > 3:
             raise
           elif e.code == 401:
@@ -372,35 +374,35 @@ class HttpRpcServer(AbstractRpcServer):
     Returns:
       A urllib2.OpenerDirector object.
     """
-    opener = urllib2.OpenerDirector()
-    opener.add_handler(urllib2.ProxyHandler())
-    opener.add_handler(urllib2.UnknownHandler())
-    opener.add_handler(urllib2.HTTPHandler())
-    opener.add_handler(urllib2.HTTPDefaultErrorHandler())
-    opener.add_handler(urllib2.HTTPSHandler())
+    opener = six.moves.urllib.request.OpenerDirector()
+    opener.add_handler(six.moves.urllib.request.ProxyHandler())
+    opener.add_handler(six.moves.urllib.request.UnknownHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPDefaultErrorHandler())
+    opener.add_handler(six.moves.urllib.request.HTTPSHandler())
     opener.add_handler(urllib2.HTTPErrorProcessor())
     if self.save_cookies:
       self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
-      self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
+      self.cookie_jar = six.moves.http_cookiejar.MozillaCookieJar(self.cookie_file)
       if os.path.exists(self.cookie_file):
         try:
           self.cookie_jar.load()
           self.authenticated = True
           StatusUpdate("Loaded authentication cookies from %s" %
                        self.cookie_file)
-        except (cookielib.LoadError, IOError):
+        except (six.moves.http_cookiejar.LoadError, IOError):
           # Failed to load cookies - just ignore them.
           pass
       else:
         # Create an empty cookie file with mode 600
-        fd = os.open(self.cookie_file, os.O_CREAT, 0600)
+        fd = os.open(self.cookie_file, os.O_CREAT, 0o600)
         os.close(fd)
       # Always chmod the cookie file
-      os.chmod(self.cookie_file, 0600)
+      os.chmod(self.cookie_file, 0o600)
     else:
       # Don't save cookies across runs of update.py.
-      self.cookie_jar = cookielib.CookieJar()
-    opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
+      self.cookie_jar = six.moves.http_cookiejar.CookieJar()
+    opener.add_handler(six.moves.urllib.request.HTTPCookieProcessor(self.cookie_jar))
     return opener
 
 
@@ -575,7 +577,7 @@ def RunShellWithReturnCode(command, print_output=False,
       line = p.stdout.readline()
       if not line:
         break
-      print line.strip("\n")
+      print(line.strip("\n"))
       output_array.append(line)
     output = "".join(output_array)
   else:
@@ -583,7 +585,7 @@ def RunShellWithReturnCode(command, print_output=False,
   p.wait()
   errout = p.stderr.read()
   if print_output and errout:
-    print >>sys.stderr, errout
+    print(errout, file=sys.stderr)
   p.stdout.close()
   p.stderr.close()
   return output, p.returncode
@@ -629,11 +631,11 @@ class VersionControlSystem(object):
     """Show an "are you sure?" prompt if there are unknown files."""
     unknown_files = self.GetUnknownFiles()
     if unknown_files:
-      print "The following files are not added to version control:"
+      print("The following files are not added to version control:")
       for line in unknown_files:
-        print line
+        print(line)
       prompt = "Are you sure to continue?(y/N) "
-      answer = raw_input(prompt).strip()
+      answer = input(prompt).strip()
       if answer != "y":
         ErrorExit("User aborted")
 
@@ -685,13 +687,13 @@ class VersionControlSystem(object):
       else:
         type = "current"
       if len(content) > MAX_UPLOAD_SIZE:
-        print ("Not uploading the %s file for %s because it's too large." %
-               (type, filename))
+        print(("Not uploading the %s file for %s because it's too large." %
+               (type, filename)))
         file_too_large = True
         content = ""
       checksum = md5.new(content).hexdigest()
       if options.verbose > 0 and not file_too_large:
-        print "Uploading %s file for %s" % (type, filename)
+        print("Uploading %s file for %s" % (type, filename))
       url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
       form_fields = [("filename", filename),
                      ("status", status),
@@ -770,8 +772,8 @@ class SubversionVCS(VersionControlSystem):
       words = line.split()
       if len(words) == 2 and words[0] == "URL:":
         url = words[1]
-        scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
-        username, netloc = urllib.splituser(netloc)
+        scheme, netloc, path, params, query, fragment = six.moves.urllib.parse.urlparse(url)
+        username, netloc = six.moves.urllib.parse.splituser(netloc)
         if username:
           logging.info("Removed username from base URL")
         if netloc.endswith("svn.python.org"):
@@ -789,12 +791,12 @@ class SubversionVCS(VersionControlSystem):
           logging.info("Guessed CollabNet base = %s", base)
         elif netloc.endswith(".googlecode.com"):
           path = path + "/"
-          base = urlparse.urlunparse(("http", netloc, path, params,
+          base = six.moves.urllib.parse.urlunparse(("http", netloc, path, params,
                                       query, fragment))
           logging.info("Guessed Google Code base = %s", base)
         else:
           path = path + "/"
-          base = urlparse.urlunparse((scheme, netloc, path, params,
+          base = six.moves.urllib.parse.urlunparse((scheme, netloc, path, params,
                                       query, fragment))
           logging.info("Guessed base = %s", base)
         return base
@@ -1202,8 +1204,8 @@ def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
   rv = []
   for patch in patches:
     if len(patch[1]) > MAX_UPLOAD_SIZE:
-      print ("Not uploading the patch for " + patch[0] +
-             " because the file is too large.")
+      print(("Not uploading the patch for " + patch[0] +
+             " because the file is too large."))
       continue
     form_fields = [("filename", patch[0])]
     if not options.download_base:
@@ -1211,7 +1213,7 @@ def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
     files = [("data", "data.diff", patch[1])]
     ctype, body = EncodeMultipartFormData(form_fields, files)
     url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
-    print "Uploading patch for " + patch[0]
+    print("Uploading patch for " + patch[0])
     response_body = rpc_server.Send(url, body, content_type=ctype)
     lines = response_body.splitlines()
     if not lines or lines[0] != "OK":
@@ -1238,7 +1240,8 @@ def GuessVCS(options):
     out, returncode = RunShellWithReturnCode(["hg", "root"])
     if returncode == 0:
       return MercurialVCS(options, out.strip())
-  except OSError, (errno, message):
+  except OSError as xxx_todo_changeme:
+    (errno, message) = xxx_todo_changeme.args
     if errno != 2:  # ENOENT -- they don't have hg installed.
       raise
 
@@ -1254,7 +1257,8 @@ def GuessVCS(options):
                                               "--is-inside-work-tree"])
     if returncode == 0:
       return GitVCS(options)
-  except OSError, (errno, message):
+  except OSError as xxx_todo_changeme1:
+    (errno, message) = xxx_todo_changeme1.args
     if errno != 2:  # ENOENT -- they don't have git installed.
       raise
 
@@ -1301,12 +1305,12 @@ def RealMain(argv, data=None):
     data = vcs.GenerateDiff(args)
   files = vcs.GetBaseFiles(data)
   if verbosity >= 1:
-    print "Upload server:", options.server, "(change with -s/--server)"
+    print("Upload server:", options.server, "(change with -s/--server)")
   if options.issue:
     prompt = "Message describing this patch set: "
   else:
     prompt = "New issue subject: "
-  message = options.message or raw_input(prompt).strip()
+  message = options.message or input(prompt).strip()
   if not message:
     ErrorExit("A non-empty message is required")
   rpc_server = GetRpcServer(options)
@@ -1339,7 +1343,7 @@ def RealMain(argv, data=None):
   # Send a hash of all the base file so the server can determine if a copy
   # already exists in an earlier patchset.
   base_hashes = ""
-  for file, info in files.iteritems():
+  for file, info in files.items():
     if not info[0] is None:
       checksum = md5.new(info[0]).hexdigest()
       if base_hashes:
@@ -1353,7 +1357,7 @@ def RealMain(argv, data=None):
   if not options.download_base:
     form_fields.append(("content_upload", "1"))
   if len(data) > MAX_UPLOAD_SIZE:
-    print "Patch is large, so uploading file patches separately."
+    print("Patch is large, so uploading file patches separately.")
     uploaded_diff_file = []
     form_fields.append(("separate_patches", "1"))
   else:
@@ -1393,7 +1397,7 @@ def main():
   try:
     RealMain(sys.argv)
   except KeyboardInterrupt:
-    print
+    print()
     StatusUpdate("Interrupted.")
     sys.exit(1)
 
diff --git a/security/nss/gtests/google_test/gtest/test/googletest-env-var-test.py b/security/nss/gtests/google_test/gtest/test/googletest-env-var-test.py
index 02c3655c39..1eb3f9c8e7 100644
--- a/security/nss/gtests/google_test/gtest/test/googletest-env-var-test.py
+++ b/security/nss/gtests/google_test/gtest/test/googletest-env-var-test.py
@@ -31,6 +31,7 @@
 
 """Verifies that Google Test correctly parses environment variables."""
 
+from __future__ import print_function
 import os
 import gtest_test_utils
 
@@ -45,8 +46,8 @@ environ = os.environ.copy()
 
 def AssertEq(expected, actual):
   if expected != actual:
-    print('Expected: %s' % (expected,))
-    print('  Actual: %s' % (actual,))
+    print(('Expected: %s' % (expected,)))
+    print(('  Actual: %s' % (actual,)))
     raise AssertionError
 
 
diff --git a/security/nss/gtests/google_test/gtest/test/googletest-throw-on-failure-test.py b/security/nss/gtests/google_test/gtest/test/googletest-throw-on-failure-test.py
index ea627c479d..028e43ff3f 100644
--- a/security/nss/gtests/google_test/gtest/test/googletest-throw-on-failure-test.py
+++ b/security/nss/gtests/google_test/gtest/test/googletest-throw-on-failure-test.py
@@ -35,6 +35,7 @@ This script invokes googletest-throw-on-failure-test_ (a program written with
 Google Test) with different environments and command line flags.
 """
 
+from __future__ import print_function
 import os
 import gtest_test_utils
 
@@ -68,7 +69,7 @@ def SetEnvVar(env_var, value):
 def Run(command):
   """Runs a command; returns True/False if its exit code is/isn't 0."""
 
-  print('Running "%s". . .' % ' '.join(command))
+  print(('Running "%s". . .' % ' '.join(command)))
   p = gtest_test_utils.Subprocess(command)
   return p.exited and p.exit_code == 0
 
diff --git a/security/nss/gtests/google_test/gtest/test/googletest-uninitialized-test.py b/security/nss/gtests/google_test/gtest/test/googletest-uninitialized-test.py
index 69595a0dde..5b726cdda8 100644
--- a/security/nss/gtests/google_test/gtest/test/googletest-uninitialized-test.py
+++ b/security/nss/gtests/google_test/gtest/test/googletest-uninitialized-test.py
@@ -31,6 +31,7 @@
 
 """Verifies that Google Test warns the user when not initialized properly."""
 
+from __future__ import print_function
 import gtest_test_utils
 
 COMMAND = gtest_test_utils.GetTestExecutablePath('googletest-uninitialized-test_')
@@ -43,8 +44,8 @@ def Assert(condition):
 
 def AssertEq(expected, actual):
   if expected != actual:
-    print('Expected: %s' % (expected,))
-    print('  Actual: %s' % (actual,))
+    print(('Expected: %s' % (expected,)))
+    print(('  Actual: %s' % (actual,)))
     raise AssertionError
 
 
diff --git a/security/nss/gtests/google_test/gtest/test/gtest_test_utils.py b/security/nss/gtests/google_test/gtest/test/gtest_test_utils.py
index d0c24466a4..3b73f136eb 100755
--- a/security/nss/gtests/google_test/gtest/test/gtest_test_utils.py
+++ b/security/nss/gtests/google_test/gtest/test/gtest_test_utils.py
@@ -31,6 +31,7 @@
 # Suppresses the 'Import not at the top of the file' lint complaint.
 # pylint: disable-msg=C6204
 
+from __future__ import print_function
 import os
 import sys
 
@@ -173,7 +174,7 @@ def GetTestExecutablePath(executable_name, build_dir=None):
         'Unable to find the test binary "%s". Please make sure to provide\n'
         'a path to the binary via the --build_dir flag or the BUILD_DIR\n'
         'environment variable.' % path)
-    print >> sys.stderr, message
+    print(message, file=sys.stderr)
     sys.exit(1)
 
   return path
diff --git a/security/nss/gtests/google_test/gtest/test/gtest_xml_test_utils.py b/security/nss/gtests/google_test/gtest/test/gtest_xml_test_utils.py
index ec42c62c3b..be5df6e0e5 100755
--- a/security/nss/gtests/google_test/gtest/test/gtest_xml_test_utils.py
+++ b/security/nss/gtests/google_test/gtest/test/gtest_xml_test_utils.py
@@ -74,8 +74,8 @@ class GTestXMLTestCase(gtest_test_utils.TestCase):
     self.assertEquals(
         expected_attributes.length, actual_attributes.length,
         'attribute numbers differ in element %s:\nExpected: %r\nActual: %r' % (
-            actual_node.tagName, expected_attributes.keys(),
-            actual_attributes.keys()))
+            actual_node.tagName, list(expected_attributes.keys()),
+            list(actual_attributes.keys())))
     for i in range(expected_attributes.length):
       expected_attr = expected_attributes.item(i)
       actual_attr = actual_attributes.get(expected_attr.name)
diff --git a/services/common/tests/mach_commands.py b/services/common/tests/mach_commands.py
index b57fa3aa26..ad016dbf3f 100644
--- a/services/common/tests/mach_commands.py
+++ b/services/common/tests/mach_commands.py
@@ -2,7 +2,6 @@
 # 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, unicode_literals
 
 import mozpack.path as mozpath
 
@@ -92,7 +91,7 @@ class SyncTestCommands(MachCommandBase):
             ]
 
         profile_dir = mkdtemp()
-        print 'Created profile directory: %s' % profile_dir
+        print('Created profile directory: %s' % profile_dir)
 
         try:
             env = {'XPCSHELL_TEST_PROFILE_DIR': profile_dir}
@@ -101,7 +100,7 @@ class SyncTestCommands(MachCommandBase):
             return proc.wait()
 
         finally:
-            print 'Removing profile directory %s' % profile_dir
+            print('Removing profile directory %s' % profile_dir)
             rmtree(profile_dir)
 
     @Command('storage-server', category='services',
diff --git a/taskcluster/taskgraph/create.py b/taskcluster/taskgraph/create.py
index f577f88731..e41d89fbdf 100644
--- a/taskcluster/taskgraph/create.py
+++ b/taskcluster/taskgraph/create.py
@@ -24,7 +24,7 @@ CONCURRENCY = 50
 
 
 def create_tasks(taskgraph, label_to_taskid, params):
-    taskid_to_label = {t: l for l, t in label_to_taskid.iteritems()}
+    taskid_to_label = {t: l for l, t in label_to_taskid.items()}
 
     session = requests.Session()
 
@@ -85,7 +85,7 @@ def create_tasks(taskgraph, label_to_taskid, params):
                                        taskid_to_label[task_id], task_def)
 
         # Wait for all futures to complete.
-        for f in futures.as_completed(fs.values()):
+        for f in futures.as_completed(list(fs.values())):
             f.result()
 
 
@@ -113,10 +113,10 @@ def resolve_timestamps(now, task_def):
         if isinstance(val, list):
             return [recurse(v) for v in val]
         elif isinstance(val, dict):
-            if val.keys() == ['relative-datestamp']:
+            if list(val.keys()) == ['relative-datestamp']:
                 return json_time_from_now(val['relative-datestamp'], now)
             else:
-                return {k: recurse(v) for k, v in val.iteritems()}
+                return {k: recurse(v) for k, v in val.items()}
         else:
             return val
     return recurse(task_def)
diff --git a/taskcluster/taskgraph/decision.py b/taskcluster/taskgraph/decision.py
index d6460390fb..caba3442c7 100644
--- a/taskcluster/taskgraph/decision.py
+++ b/taskcluster/taskgraph/decision.py
@@ -95,7 +95,7 @@ def taskgraph_decision(options):
     _, _ = TaskGraph.from_json(full_task_json)
 
     # write out the target task set to allow reproducing this as input
-    write_artifact('target-tasks.json', tgg.target_task_set.tasks.keys())
+    write_artifact('target-tasks.json', list(tgg.target_task_set.tasks.keys()))
 
     # write out the optimized task graph to describe what will actually happen,
     # and the map of labels to taskids
diff --git a/taskcluster/taskgraph/docker.py b/taskcluster/taskgraph/docker.py
index 8159fd5a4a..16b19dc02d 100644
--- a/taskcluster/taskgraph/docker.py
+++ b/taskcluster/taskgraph/docker.py
@@ -11,7 +11,7 @@ import os
 import subprocess
 import tarfile
 import tempfile
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import which
 
 from taskgraph.util import docker
@@ -28,7 +28,7 @@ def load_image_by_name(image_name):
 
     image_index_url = INDEX_URL.format('mozilla-central', image_name, context_hash)
     print("Fetching", image_index_url)
-    task = json.load(urllib2.urlopen(image_index_url))
+    task = json.load(six.moves.urllib.request.urlopen(image_index_url))
 
     return load_image_by_task_id(task['taskId'])
 
@@ -51,8 +51,8 @@ def load_image_by_task_id(task_id):
     print("Determining image name")
     tf = tarfile.open(filename)
     repositories = json.load(tf.extractfile('repositories'))
-    name = repositories.keys()[0]
-    tag = repositories[name].keys()[0]
+    name = list(repositories.keys())[0]
+    tag = list(repositories[name].keys())[0]
     name = '{}:{}'.format(name, tag)
     print("Image name:", name)
 
diff --git a/taskcluster/taskgraph/generator.py b/taskcluster/taskgraph/generator.py
index 809ed1f5c0..ec31625061 100644
--- a/taskcluster/taskgraph/generator.py
+++ b/taskcluster/taskgraph/generator.py
@@ -155,7 +155,7 @@ class TaskGraphGenerator(object):
         # in post-order
         kinds = {kind.name: kind for kind in self._load_kinds()}
         edges = set()
-        for kind in kinds.itervalues():
+        for kind in kinds.values():
             for dep in kind.config.get('kind-dependencies', []):
                 edges.add((kind.name, dep, 'kind-dependency'))
         kind_graph = Graph(set(kinds), edges)
@@ -211,7 +211,7 @@ class TaskGraphGenerator(object):
     def _run_until(self, name):
         while name not in self._run_results:
             try:
-                k, v = self._run.next()
+                k, v = next(self._run)
             except StopIteration:
                 raise AttributeError("No such run result {}".format(name))
             self._run_results[k] = v
diff --git a/taskcluster/taskgraph/optimize.py b/taskcluster/taskgraph/optimize.py
index 120e6807ba..855666c87b 100644
--- a/taskcluster/taskgraph/optimize.py
+++ b/taskcluster/taskgraph/optimize.py
@@ -51,10 +51,10 @@ def resolve_task_references(label, task_def, taskid_for_edge_name):
         if isinstance(val, list):
             return [recurse(v) for v in val]
         elif isinstance(val, dict):
-            if val.keys() == ['task-reference']:
+            if list(val.keys()) == ['task-reference']:
                 return TASK_REFERENCE_PATTERN.sub(repl, val['task-reference'])
             else:
-                return {k: recurse(v) for k, v in val.iteritems()}
+                return {k: recurse(v) for k, v in val.items()}
         else:
             return val
     return recurse(task_def)
@@ -78,7 +78,7 @@ def annotate_task_graph(target_task_graph, params, do_not_optimize,
         named_task_dependencies = named_links_dict.get(label, {})
 
         # check whether any dependencies have been optimized away
-        dependencies = [target_task_graph.tasks[l] for l in named_task_dependencies.itervalues()]
+        dependencies = [target_task_graph.tasks[l] for l in named_task_dependencies.values()]
         for t in dependencies:
             if t.optimized and not t.task_id:
                 raise Exception(
@@ -134,9 +134,9 @@ def get_subgraph(annotated_task_graph, named_links_dict, label_to_taskid):
         task.task_id = label_to_taskid[label] = slugid()
         named_task_dependencies = {
                 name: label_to_taskid[label]
-                for name, label in named_links_dict.get(label, {}).iteritems()}
+                for name, label in named_links_dict.get(label, {}.items())}
         task.task = resolve_task_references(task.label, task.task, named_task_dependencies)
-        task.task.setdefault('dependencies', []).extend(named_task_dependencies.itervalues())
+        task.task.setdefault('dependencies', []).extend(named_task_dependencies.values())
         tasks_by_taskid[task.task_id] = task
 
     # resolve edges to taskIds
diff --git a/taskcluster/taskgraph/target_tasks.py b/taskcluster/taskgraph/target_tasks.py
index d2b3f5a7f0..08a3f9c4ce 100644
--- a/taskcluster/taskgraph/target_tasks.py
+++ b/taskcluster/taskgraph/target_tasks.py
@@ -40,7 +40,7 @@ def target_tasks_try_option_syntax(full_task_graph, parameters):
     """Generate a list of target tasks based on try syntax in
     parameters['message'] and, for context, the full task graph."""
     options = try_option_syntax.TryOptionSyntax(parameters['message'], full_task_graph)
-    target_tasks_labels = [t.label for t in full_task_graph.tasks.itervalues()
+    target_tasks_labels = [t.label for t in full_task_graph.tasks.values()
                            if options.task_matches(t.attributes)]
 
     # If the developer wants test jobs to be rebuilt N times we add that value here
@@ -80,7 +80,7 @@ def target_tasks_default(full_task_graph, parameters):
             if project in RELEASE_PROJECTS:
                 return True
         return project in run_on_projects
-    return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
+    return [l for l, t in full_task_graph.tasks.items() if list(filter(t))]
 
 
 @_target_task('ash_tasks')
@@ -102,7 +102,7 @@ def target_tasks_ash(full_task_graph, parameters):
         if task.attributes['kind'] == 'upload-symbols':
             return False
         return True
-    return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
+    return [l for l, t in full_task_graph.tasks.items() if list(filter(t))]
 
 
 @_target_task('cedar_tasks')
@@ -118,4 +118,4 @@ def target_tasks_cedar(full_task_graph, parameters):
                     or 'xpcshell' in task.attributes['unittest_suite']):
                 return False
         return True
-    return [l for l, t in full_task_graph.tasks.iteritems() if filter(t)]
+    return [l for l, t in full_task_graph.tasks.items() if list(filter(t))]
diff --git a/taskcluster/taskgraph/task/base.py b/taskcluster/taskgraph/task/base.py
index 2d9cbf5d95..d64d7198d3 100644
--- a/taskcluster/taskgraph/task/base.py
+++ b/taskcluster/taskgraph/task/base.py
@@ -5,9 +5,10 @@
 from __future__ import absolute_import, print_function, unicode_literals
 
 import abc
+import six
 
 
-class Task(object):
+class Task(six.with_metaclass(abc.ABCMeta, object)):
     """
     Representation of a task in a TaskGraph.  Each Task has, at creation:
 
@@ -26,7 +27,6 @@ class Task(object):
     path from which it draws its task configuration.  The instance is free to
     store as much local state as it needs.
     """
-    __metaclass__ = abc.ABCMeta
 
     def __init__(self, kind, label, attributes, task):
         self.kind = kind
diff --git a/taskcluster/taskgraph/task/docker_image.py b/taskcluster/taskgraph/task/docker_image.py
index fd67c48328..dd8a211b04 100644
--- a/taskcluster/taskgraph/task/docker_image.py
+++ b/taskcluster/taskgraph/task/docker_image.py
@@ -7,7 +7,7 @@ from __future__ import absolute_import, print_function, unicode_literals
 import logging
 import json
 import os
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
 from . import base
 from taskgraph.util.docker import (
@@ -16,6 +16,7 @@ from taskgraph.util.docker import (
     INDEX_PREFIX,
 )
 from taskgraph.util.templates import Templates
+import six
 
 logger = logging.getLogger(__name__)
 GECKO = os.path.realpath(os.path.join(__file__, '..', '..', '..', '..'))
@@ -58,7 +59,7 @@ class DockerImageTask(base.Task):
 
         tasks = []
         templates = Templates(path)
-        for image_name, image_symbol in config['images'].iteritems():
+        for image_name, image_symbol in config['images'].items():
             context_path = os.path.join('testing', 'docker', image_name)
             context_hash = generate_context_hash(GECKO, context_path, image_name)
 
@@ -95,20 +96,20 @@ class DockerImageTask(base.Task):
         for index_path in self.index_paths:
             try:
                 url = INDEX_URL.format(index_path)
-                existing_task = json.load(urllib2.urlopen(url))
+                existing_task = json.load(six.moves.urllib.request.urlopen(url))
                 # Only return the task ID if the artifact exists for the indexed
                 # task.  Otherwise, continue on looking at each of the branches.  Method
                 # continues trying other branches in case mozilla-central has an expired
                 # artifact, but 'project' might not. Only return no task ID if all
                 # branches have been tried
-                request = urllib2.Request(
+                request = six.moves.urllib.request.Request(
                     ARTIFACT_URL.format(existing_task['taskId'], 'public/image.tar.zst'))
                 request.get_method = lambda: 'HEAD'
-                urllib2.urlopen(request)
+                six.moves.urllib.request.urlopen(request)
 
                 # HEAD success on the artifact is enough
                 return True, existing_task['taskId']
-            except urllib2.HTTPError:
+            except six.moves.urllib.error.HTTPError:
                 pass
 
         return False, None
diff --git a/taskcluster/taskgraph/task/signing.py b/taskcluster/taskgraph/task/signing.py
index a2a9ae3d66..6eff2ab751 100644
--- a/taskcluster/taskgraph/task/signing.py
+++ b/taskcluster/taskgraph/task/signing.py
@@ -33,7 +33,7 @@ class SigningTask(base.Task):
             templates = Templates(root)
             jobs = templates.load(filename, {})
 
-            for name, job in jobs.iteritems():
+            for name, job in jobs.items():
                 for artifact in job['unsigned-task']['artifacts']:
                     url = ARTIFACT_URL.format('<{}>'.format('unsigned-artifact'), artifact)
                     job['task']['payload']['unsignedArtifacts'].append({
diff --git a/taskcluster/taskgraph/task/test.py b/taskcluster/taskgraph/task/test.py
index 928f32a5a5..1309edcfbd 100644
--- a/taskcluster/taskgraph/task/test.py
+++ b/taskcluster/taskgraph/task/test.py
@@ -41,7 +41,7 @@ class TestTask(transform.TransformTask):
         test_descriptions = load_yaml(path, 'tests.yml')
 
         # generate all tests for all test platforms
-        for test_platform_name, test_platform in test_platforms.iteritems():
+        for test_platform_name, test_platform in test_platforms.items():
             for test_name in test_platform['test-names']:
                 test = copy.deepcopy(test_descriptions[test_name])
                 test['build-platform'] = test_platform['build-platform']
@@ -79,7 +79,7 @@ class TestTask(transform.TransformTask):
         based on the available build platforms.  Returns a dictionary mapping
         test platform to {test-set, build-platform, build-label}."""
         test_platforms = {}
-        for test_platform, cfg in test_platforms_cfg.iteritems():
+        for test_platform, cfg in test_platforms_cfg.items():
             build_platform = cfg['build-platform']
             if build_platform not in builds_by_platform:
                 logger.warning(
@@ -100,7 +100,7 @@ class TestTask(transform.TransformTask):
         `test-names` key for each test platform, containing a set of test
         names."""
         rv = {}
-        for test_platform, cfg in test_platforms.iteritems():
+        for test_platform, cfg in test_platforms.items():
             test_set = cfg['test-set']
             if test_set not in test_sets_cfg:
                 raise Exception(
diff --git a/taskcluster/taskgraph/task/transform.py b/taskcluster/taskgraph/task/transform.py
index 8183254a07..bc421f63be 100644
--- a/taskcluster/taskgraph/task/transform.py
+++ b/taskcluster/taskgraph/task/transform.py
@@ -48,9 +48,9 @@ class TransformTask(base.Task):
         """
         def jobs():
             defaults = config.get('job-defaults')
-            jobs = config.get('jobs', {}).iteritems()
+            jobs = config.get('jobs', {}.items())
             jobs_from = itertools.chain.from_iterable(
-                load_yaml(path, filename).iteritems()
+                load_yaml(path, filename.items())
                 for filename in config.get('jobs-from', {}))
             for name, job in itertools.chain(jobs, jobs_from):
                 if defaults:
diff --git a/taskcluster/taskgraph/taskgraph.py b/taskcluster/taskgraph/taskgraph.py
index 7736745ef5..0745588baa 100644
--- a/taskcluster/taskgraph/taskgraph.py
+++ b/taskcluster/taskgraph/taskgraph.py
@@ -52,7 +52,7 @@ class TaskGraph(object):
 
     def __iter__(self):
         "Iterate over tasks in undefined order"
-        return self.tasks.itervalues()
+        return self.tasks.values()
 
     def __repr__(self):
         return "<TaskGraph graph={!r} tasks={!r}>".format(self.graph, self.tasks)
@@ -68,7 +68,7 @@ class TaskGraph(object):
         """
         tasks = {}
         edges = set()
-        for key, value in tasks_dict.iteritems():
+        for key, value in tasks_dict.items():
             # We get the implementation from JSON
             implementation = value['kind_implementation']
             # Loading the module and creating a Task from a dictionary
@@ -76,7 +76,7 @@ class TaskGraph(object):
             tasks[key] = task_kind.from_json(value)
             if 'task_id' in value:
                 tasks[key].task_id = value['task_id']
-            for depname, dep in value['dependencies'].iteritems():
+            for depname, dep in value['dependencies'].items():
                 edges.add((key, dep, depname))
         task_graph = cls(tasks, Graph(set(tasks), edges))
         return tasks, task_graph
diff --git a/taskcluster/taskgraph/test/test_create.py b/taskcluster/taskgraph/test/test_create.py
index b8da3aec0c..56ffee86f8 100644
--- a/taskcluster/taskgraph/test/test_create.py
+++ b/taskcluster/taskgraph/test/test_create.py
@@ -46,7 +46,7 @@ class TestCreate(unittest.TestCase):
 
         create.create_tasks(taskgraph, label_to_taskid, {'level': '4'})
 
-        for tid, task in self.created_tasks.iteritems():
+        for tid, task in self.created_tasks.items():
             self.assertEqual(task['payload'], 'hello world')
             self.assertEqual(task['schedulerId'], 'gecko-level-4')
             # make sure the dependencies exist, at least
@@ -68,7 +68,7 @@ class TestCreate(unittest.TestCase):
 
         create.create_tasks(taskgraph, label_to_taskid, {'level': '4'})
 
-        for tid, task in self.created_tasks.iteritems():
+        for tid, task in self.created_tasks.items():
             self.assertEqual(task.get('dependencies'), [os.environ['TASK_ID']])
 
 
diff --git a/taskcluster/taskgraph/test/test_generator.py b/taskcluster/taskgraph/test/test_generator.py
index f1b466e4dd..4c1fea0ef1 100644
--- a/taskcluster/taskgraph/test/test_generator.py
+++ b/taskcluster/taskgraph/test/test_generator.py
@@ -102,7 +102,7 @@ class TestGenerator(unittest.TestCase):
         self.tgg = self.maketgg(['fake-t-1'])
         self.assertEqual(self.tgg.target_task_set.graph,
                          graph.Graph({'fake-t-1'}, set()))
-        self.assertEqual(self.tgg.target_task_set.tasks.keys(),
+        self.assertEqual(list(self.tgg.target_task_set.tasks.keys()),
                          ['fake-t-1'])
 
     def test_target_task_graph(self):
diff --git a/taskcluster/taskgraph/test/test_optimize.py b/taskcluster/taskgraph/test/test_optimize.py
index 8d2ddf2478..702469b9df 100644
--- a/taskcluster/taskgraph/test/test_optimize.py
+++ b/taskcluster/taskgraph/test/test_optimize.py
@@ -79,7 +79,7 @@ class TestOptimize(unittest.TestCase):
         def repl(task_id):
             return 'SLUGID' if task_id and len(task_id) == 22 else task_id
         got_annotations = {
-            t.label: (t.optimized, repl(t.task_id)) for t in graph.tasks.itervalues()
+            t.label: (t.optimized, repl(t.task_id)) for t in graph.tasks.values()
         }
         self.assertEqual(got_annotations, annotations)
 
diff --git a/taskcluster/taskgraph/test/test_transforms_base.py b/taskcluster/taskgraph/test/test_transforms_base.py
index 0a0dfcaf29..6f14eeb6a8 100644
--- a/taskcluster/taskgraph/test/test_transforms_base.py
+++ b/taskcluster/taskgraph/test/test_transforms_base.py
@@ -15,7 +15,7 @@ from voluptuous import Schema
 
 schema = Schema({
     'x': int,
-    'y': basestring,
+    'y': str,
 })
 
 transforms = TransformSequence()
@@ -55,7 +55,7 @@ class TestValidateSchema(unittest.TestCase):
         try:
             validate_schema(schema, {'x': 'not-int'}, "pfx")
             self.fail("no exception raised")
-        except Exception, e:
+        except Exception as e:
             self.failUnless(str(e).startswith("pfx\n"))
 
 
diff --git a/taskcluster/taskgraph/test/test_try_option_syntax.py b/taskcluster/taskgraph/test/test_try_option_syntax.py
index 29aa2d5a90..0ed69c1ee7 100644
--- a/taskcluster/taskgraph/test/test_try_option_syntax.py
+++ b/taskcluster/taskgraph/test/test_try_option_syntax.py
@@ -40,9 +40,9 @@ tasks = {k: v for k, v in [
     unittest_task('gtest', 'linux64'),
     talos_task('dromaeojs', 'linux64'),
 ]}
-unittest_tasks = {k: v for k, v in tasks.iteritems()
+unittest_tasks = {k: v for k, v in tasks.items()
                   if 'unittest_try_name' in v.attributes}
-talos_tasks = {k: v for k, v in tasks.iteritems()
+talos_tasks = {k: v for k, v in tasks.items()
                if 'talos_try_name' in v.attributes}
 graph_with_jobs = TaskGraph(tasks, Graph(set(tasks), set()))
 
@@ -139,7 +139,7 @@ class TestTryOptionSyntax(unittest.TestCase):
         tos = TryOptionSyntax('try: -p linux,linux64', empty_graph)
         ridealongs = list(task
                           for task in itertools.chain.from_iterable(
-                                RIDEALONG_BUILDS.itervalues()
+                                RIDEALONG_BUILDS.values()
                           )
                           if 'android' not in task)  # Don't include android-l10n
         self.assertEqual(sorted(tos.platforms), sorted(['linux', 'linux64'] + ridealongs))
diff --git a/taskcluster/taskgraph/transforms/base.py b/taskcluster/taskgraph/transforms/base.py
index aab1392521..a52ebc5025 100644
--- a/taskcluster/taskgraph/transforms/base.py
+++ b/taskcluster/taskgraph/transforms/base.py
@@ -102,7 +102,7 @@ def get_keyed_by(item, field, item_name, subfield=None):
             return value
 
     assert len(value) == 1, "Invalid attribute {} in {}".format(field, item_name)
-    keyed_by = value.keys()[0]
+    keyed_by = list(value.keys())[0]
     values = value[keyed_by]
     if keyed_by.startswith('by-'):
         keyed_by = keyed_by[3:]  # extract just the keyed-by field name
diff --git a/taskcluster/taskgraph/transforms/job/__init__.py b/taskcluster/taskgraph/transforms/job/__init__.py
index a0860c0324..52a367e65f 100644
--- a/taskcluster/taskgraph/transforms/job/__init__.py
+++ b/taskcluster/taskgraph/transforms/job/__init__.py
@@ -28,15 +28,15 @@ logger = logging.getLogger(__name__)
 
 # Voluptuous uses marker objects as dictionary *keys*, but they are not
 # comparable, so we cast all of the keys back to regular strings
-task_description_schema = {str(k): v for k, v in task_description_schema.schema.iteritems()}
+task_description_schema = {str(k): v for k, v in task_description_schema.schema.items()}
 
 # Schema for a build description
 job_description_schema = Schema({
     # The name of the job and the job's label.  At least one must be specified,
     # and the label will be generated from the name if necessary, by prepending
     # the kind.
-    Optional('name'): basestring,
-    Optional('label'): basestring,
+    Optional('name'): str,
+    Optional('label'): str,
 
     # the following fields are passed directly through to the task description,
     # possibly modified by the run implementation.  See
@@ -59,7 +59,7 @@ job_description_schema = Schema({
     # A description of how to run this job.
     'run': {
         # The key to a job implementation in a peer module to this one
-        'using': basestring,
+        'using': str,
 
         # Any remaining content is verified against that job implementation's
         # own schema.
diff --git a/taskcluster/taskgraph/transforms/job/hazard.py b/taskcluster/taskgraph/transforms/job/hazard.py
index c5b500843d..66b2ea31bc 100644
--- a/taskcluster/taskgraph/transforms/job/hazard.py
+++ b/taskcluster/taskgraph/transforms/job/hazard.py
@@ -21,20 +21,20 @@ haz_run_schema = Schema({
     Required('using'): 'hazard',
 
     # The command to run within the task image (passed through to the worker)
-    Required('command'): basestring,
+    Required('command'): str,
 
     # The tooltool manifest to use; default in the script is used if omitted
-    Optional('tooltool-manifest'): basestring,
+    Optional('tooltool-manifest'): str,
 
     # The mozconfig to use; default in the script is used if omitted
-    Optional('mozconfig'): basestring,
+    Optional('mozconfig'): str,
 
     # The set of secret names to which the task has access; these are prefixed
     # with `project/releng/gecko/{treeherder.kind}/level-{level}/`.   Setting
     # this will enable any worker features required and set the task's scopes
     # appropriately.  `true` here means ['*'], all secrets.  Not supported on
     # Windows
-    Required('secrets', default=False): Any(bool, [basestring]),
+    Required('secrets', default=False): Any(bool, [str]),
 })
 
 
diff --git a/taskcluster/taskgraph/transforms/job/mach.py b/taskcluster/taskgraph/transforms/job/mach.py
index 8df202dbcc..74f8349b3d 100644
--- a/taskcluster/taskgraph/transforms/job/mach.py
+++ b/taskcluster/taskgraph/transforms/job/mach.py
@@ -15,7 +15,7 @@ mach_schema = Schema({
     Required('using'): 'mach',
 
     # The mach command (omitting `./mach`) to run
-    Required('mach'): basestring,
+    Required('mach'): str,
 })
 
 
diff --git a/taskcluster/taskgraph/transforms/job/mozharness.py b/taskcluster/taskgraph/transforms/job/mozharness.py
index fb3cd00dd8..f85acc2135 100644
--- a/taskcluster/taskgraph/transforms/job/mozharness.py
+++ b/taskcluster/taskgraph/transforms/job/mozharness.py
@@ -28,22 +28,22 @@ mozharness_run_schema = Schema({
 
     # the mozharness script used to run this task, relative to the testing/
     # directory and using forward slashes even on Windows
-    Required('script'): basestring,
+    Required('script'): str,
 
     # the config files required for the task, relative to
     # testing/mozharness/configs and using forward slashes even on Windows
-    Required('config'): [basestring],
+    Required('config'): [str],
 
     # any additional actions to pass to the mozharness command; not supported
     # on Windows
-    Optional('actions'): [basestring],
+    Optional('actions'): [str],
 
     # any additional options (without leading --) to be passed to mozharness;
     # not supported on Windows
-    Optional('options'): [basestring],
+    Optional('options'): [str],
 
     # --custom-build-variant-cfg value (not supported on Windows)
-    Optional('custom-build-variant-cfg'): basestring,
+    Optional('custom-build-variant-cfg'): str,
 
     # If not false, tooltool downloads will be enabled via relengAPIProxy
     # for either just public files, or all files.  Not supported on Windows
@@ -58,7 +58,7 @@ mozharness_run_schema = Schema({
     # this will enable any worker features required and set the task's scopes
     # appropriately.  `true` here means ['*'], all secrets.  Not supported on
     # Windows
-    Required('secrets', default=False): Any(bool, [basestring]),
+    Required('secrets', default=False): Any(bool, [str]),
 
     # If true, taskcluster proxy will be enabled; note that it may also be enabled
     # automatically e.g., for secrets support.  Not supported on Windows.
@@ -72,7 +72,7 @@ mozharness_run_schema = Schema({
     Required('keep-artifacts', default=True): bool,
 
     # If specified, use the in-tree job script specified.
-    Optional('job-script'): basestring,
+    Optional('job-script'): str,
 })
 
 
diff --git a/taskcluster/taskgraph/transforms/job/run_task.py b/taskcluster/taskgraph/transforms/job/run_task.py
index 296fe43eee..b035873147 100644
--- a/taskcluster/taskgraph/transforms/job/run_task.py
+++ b/taskcluster/taskgraph/transforms/job/run_task.py
@@ -28,7 +28,7 @@ run_task_schema = Schema({
     # The command arguments to pass to the `run-task` script, after the
     # checkout arguments.  If a list, it will be passed directly; otherwise
     # it will be included in a single argument to `bash -cx`.
-    Required('command'): Any([basestring], basestring),
+    Required('command'): Any([str], str),
 })
 
 
@@ -49,7 +49,7 @@ def docker_worker_run_task(config, job, taskdesc):
         })
 
     run_command = run['command']
-    if isinstance(run_command, basestring):
+    if isinstance(run_command, str):
         run_command = ['bash', '-cx', run_command]
     command = ['/home/worker/bin/run-task']
     if run['checkout']:
diff --git a/taskcluster/taskgraph/transforms/job/spidermonkey.py b/taskcluster/taskgraph/transforms/job/spidermonkey.py
index d78b785046..afac6e4f0f 100644
--- a/taskcluster/taskgraph/transforms/job/spidermonkey.py
+++ b/taskcluster/taskgraph/transforms/job/spidermonkey.py
@@ -19,11 +19,11 @@ sm_run_schema = Schema({
     Required('using'): Any('spidermonkey', 'spidermonkey-package', 'spidermonkey-mozjs-crate'),
 
     # The SPIDERMONKEY_VARIANT
-    Required('spidermonkey-variant'): basestring,
+    Required('spidermonkey-variant'): str,
 
     # The tooltool manifest to use; default from sm-tooltool-config.sh  is used
     # if omitted
-    Optional('tooltool-manifest'): basestring,
+    Optional('tooltool-manifest'): str,
 })
 
 
diff --git a/taskcluster/taskgraph/transforms/job/toolchain.py b/taskcluster/taskgraph/transforms/job/toolchain.py
index d814f78249..cad067f7ee 100644
--- a/taskcluster/taskgraph/transforms/job/toolchain.py
+++ b/taskcluster/taskgraph/transforms/job/toolchain.py
@@ -19,7 +19,7 @@ toolchain_run_schema = Schema({
     Required('using'): 'toolchain-script',
 
     # the script (in taskcluster/scripts/misc) to run
-    Required('script'): basestring,
+    Required('script'): str,
 })
 
 
diff --git a/taskcluster/taskgraph/transforms/l10n.py b/taskcluster/taskgraph/transforms/l10n.py
index 42137b5581..bb07858442 100644
--- a/taskcluster/taskgraph/transforms/l10n.py
+++ b/taskcluster/taskgraph/transforms/l10n.py
@@ -21,10 +21,7 @@ def mh_config_replace_project(config, jobs):
             # Nothing to do, not mozharness
             yield job
             continue
-        job['run']['config'] = map(
-            lambda x: x.format(project=config.params['project']),
-            job['run']['config']
-            )
+        job['run']['config'] = [x.format(project=config.params['project']) for x in job['run']['config']]
         yield job
 
 
@@ -37,8 +34,5 @@ def mh_options_replace_project(config, jobs):
             # Nothing to do, not mozharness
             yield job
             continue
-        job['run']['options'] = map(
-            lambda x: x.format(project=config.params['project']),
-            job['run']['options']
-            )
+        job['run']['options'] = [x.format(project=config.params['project']) for x in job['run']['options']]
         yield job
diff --git a/taskcluster/taskgraph/transforms/task.py b/taskcluster/taskgraph/transforms/task.py
index 6e371e4baa..d4d2cc08cf 100644
--- a/taskcluster/taskgraph/transforms/task.py
+++ b/taskcluster/taskgraph/transforms/task.py
@@ -24,40 +24,40 @@ from .gecko_v2_whitelist import JOB_NAME_WHITELIST, JOB_NAME_WHITELIST_ERROR
 
 # shortcut for a string where task references are allowed
 taskref_or_string = Any(
-    basestring,
-    {Required('task-reference'): basestring})
+    str,
+    {Required('task-reference'): str})
 
 # A task description is a general description of a TaskCluster task
 task_description_schema = Schema({
     # the label for this task
-    Required('label'): basestring,
+    Required('label'): str,
 
     # description of the task (for metadata)
-    Required('description'): basestring,
+    Required('description'): str,
 
     # attributes for this task
-    Optional('attributes'): {basestring: object},
+    Optional('attributes'): {str: object},
 
     # dependencies of this task, keyed by name; these are passed through
     # verbatim and subject to the interpretation of the Task's get_dependencies
     # method.
-    Optional('dependencies'): {basestring: object},
+    Optional('dependencies'): {str: object},
 
     # expiration and deadline times, relative to task creation, with units
     # (e.g., "14 days").  Defaults are set based on the project.
-    Optional('expires-after'): basestring,
-    Optional('deadline-after'): basestring,
+    Optional('expires-after'): str,
+    Optional('deadline-after'): str,
 
     # custom routes for this task; the default treeherder routes will be added
     # automatically
-    Optional('routes'): [basestring],
+    Optional('routes'): [str],
 
     # custom scopes for this task; any scopes required for the worker will be
     # added automatically
-    Optional('scopes'): [basestring],
+    Optional('scopes'): [str],
 
     # custom "task.extra" content
-    Optional('extra'): {basestring: object},
+    Optional('extra'): {str: object},
 
     # treeherder-related information; see
     # https://schemas.taskcluster.net/taskcluster-treeherder/v1/task-treeherder-config.json
@@ -65,7 +65,7 @@ task_description_schema = Schema({
     # added to the task
     Optional('treeherder'): {
         # either a bare symbol, or "grp(sym)".
-        'symbol': basestring,
+        'symbol': str,
 
         # the job kind
         'kind': Any('build', 'test', 'other'),
@@ -76,7 +76,7 @@ task_description_schema = Schema({
         # task platform, in the form platform/collection, used to set
         # treeherder.machine.platform and treeherder.collection or
         # treeherder.labels
-        'platform': basestring,
+        'platform': str,
 
         # treeherder environments (defaults to both staging and production)
         Required('environments', default=['production', 'staging']): ['production', 'staging'],
@@ -92,15 +92,15 @@ task_description_schema = Schema({
         'job-name': Any(
             # Assuming the job is named "normally", this is the v2 job name,
             # and the v1 and buildbot routes will be determined appropriately.
-            basestring,
+            str,
 
             # otherwise, give separate names for each of the legacy index
             # routes; if a name is omitted, no corresponding route will be
             # created.
             {
                 # the name as it appears in buildbot routes
-                Optional('buildbot'): basestring,
-                Required('gecko-v2'): basestring,
+                Optional('buildbot'): str,
+                Required('gecko-v2'): str,
             }
         ),
 
@@ -128,17 +128,17 @@ task_description_schema = Schema({
     # The `run_on_projects` attribute, defaulting to "all".  This dictates the
     # projects on which this task should be included in the target task set.
     # See the attributes documentation for details.
-    Optional('run-on-projects'): [basestring],
+    Optional('run-on-projects'): [str],
 
     # If the task can be coalesced, this is the name used in the coalesce key
     # the project, etc. will be added automatically.  Note that try (level 1)
     # tasks are never coalesced
-    Optional('coalesce-name'): basestring,
+    Optional('coalesce-name'): str,
 
     # the provisioner-id/worker-type for the task.  The following parameters will
     # be substituted in this string:
     #  {level} -- the scm level of this push
-    'worker-type': basestring,
+    'worker-type': str,
 
     # information specific to the worker implementation that will run this task
     'worker': Any({
@@ -150,9 +150,9 @@ task_description_schema = Schema({
         # generally `desktop-test`, or an image that acts an awful lot like it.
         Required('docker-image'): Any(
             # a raw Docker image path (repo/image:tag)
-            basestring,
+            str,
             # an in-tree generated docker image (from `testing/docker/<name>`)
-            {'in-tree': basestring}
+            {'in-tree': str}
         ),
 
         # worker features that should be enabled
@@ -170,10 +170,10 @@ task_description_schema = Schema({
 
             # name of the cache, allowing re-use by subsequent tasks naming the
             # same cache
-            'name': basestring,
+            'name': str,
 
             # location in the task image where the cache will be mounted
-            'mount-point': basestring,
+            'mount-point': str,
         }],
 
         # artifacts to extract from the task image after completion
@@ -182,15 +182,15 @@ task_description_schema = Schema({
             'type': Any('file', 'directory'),
 
             # task image path from which to read artifact
-            'path': basestring,
+            'path': str,
 
             # name of the produced artifact (root of the names for
             # type=directory)
-            'name': basestring,
+            'name': str,
         }],
 
         # environment variables
-        Required('env', default={}): {basestring: taskref_or_string},
+        Required('env', default={}): {str: taskref_or_string},
 
         # the command to run
         'command': [taskref_or_string],
@@ -214,53 +214,53 @@ task_description_schema = Schema({
             'type': Any('file', 'directory'),
 
             # task image path from which to read artifact
-            'path': basestring,
+            'path': str,
         }],
 
         # directories and/or files to be mounted
         Optional('mounts'): [{
             # a unique name for the cache volume
-            'cache-name': basestring,
+            'cache-name': str,
 
             # task image path for the cache
-            'path': basestring,
+            'path': str,
         }],
 
         # environment variables
-        Required('env', default={}): {basestring: taskref_or_string},
+        Required('env', default={}): {str: taskref_or_string},
 
         # the maximum time to run, in seconds
         'max-run-time': int,
 
         # os user groups for test task workers
-        Optional('os-groups', default=[]): [basestring],
+        Optional('os-groups', default=[]): [str],
     }, {
         Required('implementation'): 'buildbot-bridge',
 
         # see
         # https://github.com/mozilla/buildbot-bridge/blob/master/bbb/schemas/payload.yml
-        'buildername': basestring,
+        'buildername': str,
         'sourcestamp': {
-            'branch': basestring,
-            Optional('revision'): basestring,
-            Optional('repository'): basestring,
-            Optional('project'): basestring,
+            'branch': str,
+            Optional('revision'): str,
+            Optional('repository'): str,
+            Optional('project'): str,
         },
         'properties': {
-            'product': basestring,
-            Extra: basestring,  # additional properties are allowed
+            'product': str,
+            Extra: str,  # additional properties are allowed
         },
     }, {
         'implementation': 'macosx-engine',
 
         # A link for an executable to download
-        Optional('link'): basestring,
+        Optional('link'): str,
 
         # the command to run
         Required('command'): [taskref_or_string],
 
         # environment variables
-        Optional('env'): {basestring: taskref_or_string},
+        Optional('env'): {str: taskref_or_string},
 
         # artifacts to extract from the task image after completion
         Optional('artifacts'): [{
@@ -268,11 +268,11 @@ task_description_schema = Schema({
             Required('type'): Any('file', 'directory'),
 
             # task image path from which to read artifact
-            Required('path'): basestring,
+            Required('path'): str,
 
             # name of the produced artifact (root of the names for
             # type=directory)
-            Required('name'): basestring,
+            Required('name'): str,
         }],
     }),
 
@@ -283,7 +283,7 @@ task_description_schema = Schema({
         # This task only needs to be run if a file matching one of the given
         # patterns has changed in the push.  The patterns use the mozpack
         # match function (python/mozbuild/mozpack/path.py).
-        Optional('files-changed'): [basestring],
+        Optional('files-changed'): [str],
     }),
 })
 
@@ -457,12 +457,12 @@ def build_generic_worker_payload(config, task, task_def):
 @payload_builder('macosx-engine')
 def build_macosx_engine_payload(config, task, task_def):
     worker = task['worker']
-    artifacts = map(lambda artifact: {
+    artifacts = [{
         'name': artifact['name'],
         'path': artifact['path'],
         'type': artifact['type'],
         'expires': task_def['expires'],
-    }, worker['artifacts'])
+    } for artifact in worker['artifacts']]
 
     task_def['payload'] = {
         'link': worker['link'],
@@ -494,7 +494,7 @@ def add_index_routes(config, tasks):
 
         job_name = index['job-name']
         # unpack the v2 name to v1 and buildbot names
-        if isinstance(job_name, basestring):
+        if isinstance(job_name, str):
             base_name, type_name = job_name.rsplit('-', 1)
             job_name = {
                 'buildbot': base_name,
diff --git a/taskcluster/taskgraph/transforms/tests/make_task_description.py b/taskcluster/taskgraph/transforms/tests/make_task_description.py
index fc3f948930..1e29558d6b 100644
--- a/taskcluster/taskgraph/transforms/tests/make_task_description.py
+++ b/taskcluster/taskgraph/transforms/tests/make_task_description.py
@@ -248,7 +248,7 @@ def docker_worker_setup(config, test, taskdesc):
         elif mozharness['chunking-args'] == 'test-suite-suffix':
             suffix = mozharness['chunk-suffix'].replace('<CHUNK>', str(test['this-chunk']))
             for i, c in enumerate(command):
-                if isinstance(c, basestring) and c.startswith('--test-suite'):
+                if isinstance(c, str) and c.startswith('--test-suite'):
                     command[i] += suffix
 
     if 'download-symbols' in mozharness:
@@ -352,7 +352,7 @@ def generic_worker_setup(config, test, taskdesc):
     mh_command.extend(['--installer-url', installer_url])
     mh_command.extend(['--test-packages-url', test_packages_url])
     if mozharness.get('download-symbols'):
-        if isinstance(mozharness['download-symbols'], basestring):
+        if isinstance(mozharness['download-symbols'], str):
             mh_command.extend(['--download-symbols', mozharness['download-symbols']])
         else:
             mh_command.extend(['--download-symbols', 'true'])
@@ -366,7 +366,7 @@ def generic_worker_setup(config, test, taskdesc):
         elif mozharness['chunking-args'] == 'test-suite-suffix':
             suffix = mozharness['chunk-suffix'].replace('<CHUNK>', str(test['this-chunk']))
             for i, c in enumerate(mh_command):
-                if isinstance(c, basestring) and c.startswith('--test-suite'):
+                if isinstance(c, str) and c.startswith('--test-suite'):
                     mh_command[i] += suffix
 
     worker['command'] = [
@@ -436,7 +436,7 @@ def macosx_engine_setup(config, test, taskdesc):
         elif mozharness['chunking-args'] == 'test-suite-suffix':
             suffix = mozharness['chunk-suffix'].replace('<CHUNK>', str(test['this-chunk']))
             for i, c in enumerate(command):
-                if isinstance(c, basestring) and c.startswith('--test-suite'):
+                if isinstance(c, str) and c.startswith('--test-suite'):
                     command[i] += suffix
 
     if 'download-symbols' in mozharness:
diff --git a/taskcluster/taskgraph/transforms/tests/test_description.py b/taskcluster/taskgraph/transforms/tests/test_description.py
index 1365919fe3..293802f612 100644
--- a/taskcluster/taskgraph/transforms/tests/test_description.py
+++ b/taskcluster/taskgraph/transforms/tests/test_description.py
@@ -29,37 +29,37 @@ from voluptuous import (
 # *****WARNING*****
 test_description_schema = Schema({
     # description of the suite, for the task metadata
-    'description': basestring,
+    'description': str,
 
     # test suite name, or <suite>/<flavor>
     Required('suite'): Any(
-        basestring,
-        {'by-test-platform': {basestring: basestring}},
+        str,
+        {'by-test-platform': {str: str}},
     ),
 
     # the name by which this test suite is addressed in try syntax; defaults to
     # the test-name
-    Optional('unittest-try-name'): basestring,
+    Optional('unittest-try-name'): str,
 
     # the symbol, or group(symbol), under which this task should appear in
     # treeherder.
-    'treeherder-symbol': basestring,
+    'treeherder-symbol': str,
 
     # the value to place in task.extra.treeherder.machine.platform; ideally
     # this is the same as build-platform, and that is the default, but in
     # practice it's not always a match.
-    Optional('treeherder-machine-platform'): basestring,
+    Optional('treeherder-machine-platform'): str,
 
     # attributes to appear in the resulting task (later transforms will add the
     # common attributes)
-    Optional('attributes'): {basestring: object},
+    Optional('attributes'): {str: object},
 
     # The `run_on_projects` attribute, defaulting to "all".  This dictates the
     # projects on which this task should be included in the target task set.
     # See the attributes documentation for details.
     Optional('run-on-projects', default=['all']): Any(
-        [basestring],
-        {'by-test-platform': {basestring: [basestring]}},
+        [str],
+        {'by-test-platform': {str: [str]}},
     ),
 
     # the sheriffing tier for this task (default: set based on test platform)
@@ -70,12 +70,12 @@ test_description_schema = Schema({
     # test platform is not found, the key 'default' will be tried.
     Required('chunks', default=1): Any(
         int,
-        {'by-test-platform': {basestring: int}},
+        {'by-test-platform': {str: int}},
     ),
 
     # the time (with unit) after which this task is deleted; default depends on
     # the branch (see below)
-    Optional('expires-after'): basestring,
+    Optional('expires-after'): str,
 
     # Whether to run this task with e10s (desktop-test only).  If false, run
     # without e10s; if true, run with e10s; if 'both', run one task with and
@@ -83,13 +83,13 @@ test_description_schema = Schema({
     # and treeherder group.
     Required('e10s', default='both'): Any(
         bool, 'both',
-        {'by-test-platform': {basestring: Any(bool, 'both')}},
+        {'by-test-platform': {str: Any(bool, 'both')}},
     ),
 
     # The EC2 instance size to run these tests on.
     Required('instance-size', default='default'): Any(
         Any('default', 'large', 'xlarge', 'legacy'),
-        {'by-test-platform': {basestring: Any('default', 'large', 'xlarge', 'legacy')}},
+        {'by-test-platform': {str: Any('default', 'large', 'xlarge', 'legacy')}},
     ),
 
     # Whether the task requires loopback audio or video (whatever that may mean
@@ -119,16 +119,16 @@ test_description_schema = Schema({
     # generally `desktop-test`, or an image that acts an awful lot like it.
     Required('docker-image', default={'in-tree': 'desktop-test'}): Any(
         # a raw Docker image path (repo/image:tag)
-        basestring,
+        str,
         # an in-tree generated docker image (from `testing/docker/<name>`)
-        {'in-tree': basestring}
+        {'in-tree': str}
     ),
 
     # seconds of runtime after which the task will be killed.  Like 'chunks',
     # this can be keyed by test pltaform.
     Required('max-run-time', default=3600): Any(
         int,
-        {'by-test-platform': {basestring: int}},
+        {'by-test-platform': {str: int}},
     ),
 
     # the exit status code that indicates the task should be retried
@@ -140,27 +140,27 @@ test_description_schema = Schema({
     # What to run
     Required('mozharness'): Any({
         # the mozharness script used to run this task
-        Required('script'): basestring,
+        Required('script'): str,
 
         # the config files required for the task
         Required('config'): Any(
-            [basestring],
-            {'by-test-platform': {basestring: [basestring]}},
+            [str],
+            {'by-test-platform': {str: [str]}},
         ),
 
         # any additional actions to pass to the mozharness command
-        Optional('actions'): [basestring],
+        Optional('actions'): [str],
 
         # additional command-line options for mozharness, beyond those
         # automatically added
         Required('extra-options', default=[]): Any(
-            [basestring],
-            {'by-test-platform': {basestring: [basestring]}},
+            [str],
+            {'by-test-platform': {str: [str]}},
         ),
 
         # the artifact name (including path) to test on the build task; this is
         # generally set in a per-kind transformation
-        Optional('build-artifact-name'): basestring,
+        Optional('build-artifact-name'): str,
 
         # If true, tooltool downloads will be enabled via relengAPIProxy.
         Required('tooltool-downloads', default=False): bool,
@@ -197,7 +197,7 @@ test_description_schema = Schema({
         # the string to append to the `--test-suite` arugment when
         # chunking-args = test-suite-suffix; "<CHUNK>" in this string will
         # be replaced with the chunk number.
-        Optional('chunk-suffix'): basestring,
+        Optional('chunk-suffix'): str,
     }),
 
     # The current chunk; this is filled in by `all_kinds.py`
@@ -206,24 +206,24 @@ test_description_schema = Schema({
     # os user groups for test task workers; required scopes, will be
     # added automatically
     Optional('os-groups', default=[]): Any(
-        [basestring],
+        [str],
         # todo: create a dedicated elevated worker group and name here
-        {'by-test-platform': {basestring: [basestring]}},
+        {'by-test-platform': {str: [str]}},
     ),
 
     # -- values supplied by the task-generation infrastructure
 
     # the platform of the build this task is testing
-    'build-platform': basestring,
+    'build-platform': str,
 
     # the label of the build task generating the materials to test
-    'build-label': basestring,
+    'build-label': str,
 
     # the platform on which the tests will run
-    'test-platform': basestring,
+    'test-platform': str,
 
     # the name of the test (the key in tests.yml)
-    'test-name': basestring,
+    'test-name': str,
 
 }, required=True)
 
diff --git a/taskcluster/taskgraph/try_option_syntax.py b/taskcluster/taskgraph/try_option_syntax.py
index b5988db981..609a7c0d23 100644
--- a/taskcluster/taskgraph/try_option_syntax.py
+++ b/taskcluster/taskgraph/try_option_syntax.py
@@ -259,8 +259,8 @@ class TryOptionSyntax(object):
     def parse_build_types(self, build_types_arg):
         if build_types_arg is None:
             build_types_arg = []
-        build_types = filter(None, [BUILD_TYPE_ALIASES.get(build_type) for
-                             build_type in build_types_arg])
+        build_types = [_f for _f in [BUILD_TYPE_ALIASES.get(build_type) for
+                             build_type in build_types_arg] if _f]
         return build_types
 
     def parse_platforms(self, platform_arg):
@@ -294,7 +294,7 @@ class TryOptionSyntax(object):
             return []
 
         all_platforms = set(t.attributes['test_platform']
-                            for t in full_task_graph.tasks.itervalues()
+                            for t in full_task_graph.tasks.values()
                             if 'test_platform' in t.attributes)
 
         tests = self.parse_test_opts(test_arg, all_platforms)
@@ -303,7 +303,7 @@ class TryOptionSyntax(object):
             return []
 
         all_tests = set(t.attributes[attr_name]
-                        for t in full_task_graph.tasks.itervalues()
+                        for t in full_task_graph.tasks.values()
                         if attr_name in t.attributes)
 
         # Special case where tests is 'all' and must be expanded
@@ -455,12 +455,12 @@ class TryOptionSyntax(object):
                 results.extend(self.handle_alias(test, all_tests))
 
         # uniquify the results over the test names
-        results = {test['test']: test for test in results}.values()
+        results = list({test['test']: test for test in results}.values())
         return results
 
     def find_all_attribute_suffixes(self, graph, prefix):
         rv = set()
-        for t in graph.tasks.itervalues():
+        for t in graph.tasks.values():
             for a in t.attributes:
                 if a.startswith(prefix):
                     rv.add(a[len(prefix):])
diff --git a/taskcluster/taskgraph/util/attributes.py b/taskcluster/taskgraph/util/attributes.py
index b44a3364f1..8a37392d63 100644
--- a/taskcluster/taskgraph/util/attributes.py
+++ b/taskcluster/taskgraph/util/attributes.py
@@ -11,7 +11,7 @@ def attrmatch(attributes, **kwargs):
     must be in the set.  A callable is called with the attribute value.  If an
     attribute is specified as a keyword argument but not present in the
     attributes, the result is False."""
-    for kwkey, kwval in kwargs.iteritems():
+    for kwkey, kwval in kwargs.items():
         if kwkey not in attributes:
             return False
         attval = attributes[kwkey]
diff --git a/taskcluster/taskgraph/util/seta.py b/taskcluster/taskgraph/util/seta.py
index a0cd30675a..f18083790d 100644
--- a/taskcluster/taskgraph/util/seta.py
+++ b/taskcluster/taskgraph/util/seta.py
@@ -43,7 +43,7 @@ class SETA(object):
                              kwargs={'timeout': 5, 'headers': headers})
             task_list = json.loads(response.content).get('jobtypes', '')
             if len(task_list) > 0:
-                low_value_tasks = task_list.values()[0]
+                low_value_tasks = list(task_list.values())[0]
 
             # Bug 1315145, disable SETA for tier-1 platforms until backfill is implemented.
             low_value_tasks = [x for x in low_value_tasks if x.find('debug') == -1]
diff --git a/testing/docker/funsize-update-generator/scripts/funsize.py b/testing/docker/funsize-update-generator/scripts/funsize.py
index fd591817c1..3068de5b36 100755
--- a/testing/docker/funsize-update-generator/scripts/funsize.py
+++ b/testing/docker/funsize-update-generator/scripts/funsize.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import ConfigParser
+import six.moves.configparser
 import argparse
 import functools
 import hashlib
@@ -83,7 +83,7 @@ def get_option(directory, filename, section, option):
     log.debug("Exctracting [%s]: %s from %s/**/%s", section, option, directory,
               filename)
     f = find_file(directory, filename)
-    config = ConfigParser.ConfigParser()
+    config = six.moves.configparser.ConfigParser()
     config.read(f)
     rv = config.get(section, option)
     log.debug("Found %s", rv)
diff --git a/testing/docker/recipes/tooltool.py b/testing/docker/recipes/tooltool.py
index 952f9a5a7f..ed75536800 100755
--- a/testing/docker/recipes/tooltool.py
+++ b/testing/docker/recipes/tooltool.py
@@ -22,8 +22,9 @@
 # in which the manifest file resides and it should be called
 # 'manifest.tt'
 
+from __future__ import print_function
 import hashlib
-import httplib
+import six.moves.http_client
 import json
 import logging
 import optparse
@@ -34,12 +35,13 @@ import tarfile
 import tempfile
 import threading
 import time
-import urllib2
-import urlparse
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.parse
 import zipfile
 
 from subprocess import PIPE
 from subprocess import Popen
+import six
 
 __version__ = '1'
 
@@ -308,7 +310,7 @@ class Manifest(object):
             rv = json.dump(
                 self.file_records, output_file, indent=0, cls=FileRecordJSONEncoder,
                 separators=(',', ': '))
-            print >> output_file, ''
+            print('', file=output_file)
             return rv
 
     def dumps(self, fmt='json'):
@@ -367,9 +369,9 @@ def list_manifest(manifest_file):
         ))
         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
 
 
@@ -460,7 +462,7 @@ def fetch_file(base_urls, file_record, grabchunk=1024 * 4, auth_file=None, regio
     fetched_path = None
     for base_url in base_urls:
         # Generate the URL for the file on the server side
-        url = urlparse.urljoin(base_url,
+        url = six.moves.urllib.parse.urljoin(base_url,
                                '%s/%s' % (file_record.algorithm, file_record.digest))
         if region is not None:
             url += '?region=' + region
@@ -469,9 +471,9 @@ def fetch_file(base_urls, file_record, grabchunk=1024 * 4, auth_file=None, regio
 
         # Well, the file doesn't exist locally.  Let's fetch it.
         try:
-            req = urllib2.Request(url)
+            req = six.moves.urllib.request.Request(url)
             _authorize(req, auth_file)
-            f = urllib2.urlopen(req)
+            f = six.moves.urllib.request.urlopen(req)
             log.debug("opened %s for reading" % url)
             with open(temp_path, 'wb') as out:
                 k = True
@@ -488,7 +490,7 @@ def fetch_file(base_urls, file_record, grabchunk=1024 * 4, auth_file=None, regio
                          (file_record.filename, base_url, temp_path))
                 fetched_path = temp_path
                 break
-        except (urllib2.URLError, urllib2.HTTPError, ValueError) as e:
+        except (six.moves.urllib.error.URLError, six.moves.urllib.error.HTTPError, ValueError) as e:
             log.info("...failed to fetch '%s' from %s" %
                      (file_record.filename, base_url))
             log.debug("%s" % e)
@@ -668,7 +670,7 @@ def fetch_files(manifest_file, base_urls, filenames=[], cache_folder=None,
                 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, 0o700)
                     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,
@@ -759,14 +761,14 @@ def _authorize(req, auth_file):
 
 
 def _send_batch(base_url, auth_file, batch, region):
-    url = urlparse.urljoin(base_url, 'upload')
+    url = six.moves.urllib.parse.urljoin(base_url, 'upload')
     if region is not None:
         url += "?region=" + region
-    req = urllib2.Request(url, json.dumps(batch), {'Content-Type': 'application/json'})
+    req = six.moves.urllib.request.Request(url, json.dumps(batch), {'Content-Type': 'application/json'})
     _authorize(req, auth_file)
     try:
-        resp = urllib2.urlopen(req)
-    except (urllib2.URLError, urllib2.HTTPError) as e:
+        resp = six.moves.urllib.request.urlopen(req)
+    except (six.moves.urllib.error.URLError, six.moves.urllib.error.HTTPError) as e:
         _log_api_error(e)
         return None
     return json.load(resp)['result']
@@ -774,8 +776,8 @@ def _send_batch(base_url, auth_file, batch, region):
 
 def _s3_upload(filename, file):
     # urllib2 does not support streaming, so we fall back to good old httplib
-    url = urlparse.urlparse(file['put_url'])
-    cls = httplib.HTTPSConnection if url.scheme == 'https' else httplib.HTTPConnection
+    url = six.moves.urllib.parse.urlparse(file['put_url'])
+    cls = six.moves.http_client.HTTPSConnection if url.scheme == 'https' else six.moves.http_client.HTTPConnection
     host, port = url.netloc.split(':') if ':' in url.netloc else (url.netloc, 443)
     port = int(port)
     conn = cls(host, port)
@@ -797,14 +799,14 @@ def _s3_upload(filename, file):
 
 
 def _notify_upload_complete(base_url, auth_file, file):
-    req = urllib2.Request(
-        urlparse.urljoin(
+    req = six.moves.urllib.request.Request(
+        six.moves.urllib.parse.urljoin(
             base_url,
             'upload/complete/%(algorithm)s/%(digest)s' % file))
     _authorize(req, auth_file)
     try:
-        urllib2.urlopen(req)
-    except urllib2.HTTPError as e:
+        six.moves.urllib.request.urlopen(req)
+    except six.moves.urllib.error.HTTPError as e:
         if e.code != 409:
             _log_api_error(e)
             return
@@ -855,7 +857,7 @@ def upload(manifest, message, base_urls, auth_file, region):
     # Upload the files, each in a thread.  This allows us to start all of the
     # uploads before any of the URLs expire.
     threads = {}
-    for filename, file in files.iteritems():
+    for filename, file in files.items():
         if 'put_url' in file:
             log.info("%s: starting upload" % (filename,))
             thd = threading.Thread(target=_s3_upload,
@@ -885,7 +887,7 @@ def upload(manifest, message, base_urls, auth_file, region):
     # notify the server that the uploads are completed.  If the notification
     # fails, we don't consider that an error (the server will notice
     # eventually)
-    for filename, file in files.iteritems():
+    for filename, file in files.items():
         if 'put_url' in file and file['upload_ok']:
             log.info("notifying server of upload completion for %s" % (filename,))
             _notify_upload_complete(base_urls[0], auth_file, file)
diff --git a/testing/docker/rust-build/repack_rust.py b/testing/docker/rust-build/repack_rust.py
index e0a5e89c5f..bad93db043 100644
--- a/testing/docker/rust-build/repack_rust.py
+++ b/testing/docker/rust-build/repack_rust.py
@@ -5,6 +5,7 @@ with the necessary tool and target support for the Firefox
 build environment.
 '''
 
+from __future__ import print_function
 import os.path
 import requests
 import subprocess
@@ -24,12 +25,12 @@ def fetch_file(url):
 def fetch(url):
   '''Download and verify a package url.'''
   base = os.path.basename(url)
-  print('Fetching %s...' % base)
+  print(('Fetching %s...' % base))
   fetch_file(url + '.asc')
   fetch_file(url)
   fetch_file(url + '.sha256')
   fetch_file(url + '.asc.sha256')
-  print('Verifying %s...' % base)
+  print(('Verifying %s...' % base))
   subprocess.check_call(['shasum', '-c', base + '.sha256'])
   subprocess.check_call(['shasum', '-c', base + '.asc.sha256'])
   subprocess.check_call(['gpg', '--verify', base + '.asc', base])
@@ -40,15 +41,15 @@ def fetch(url):
 
 def install(filename, target):
   '''Run a package's installer script against the given target directory.'''
-  print(' Unpacking %s...' % filename)
+  print((' Unpacking %s...' % filename))
   subprocess.check_call(['tar', 'xf', filename])
   basename = filename.split('.tar')[0]
-  print(' Installing %s...' % basename)
+  print((' Installing %s...' % basename))
   install_cmd = [os.path.join(basename, 'install.sh')]
   install_cmd += ['--prefix=' + os.path.abspath(target)]
   install_cmd += ['--disable-ldconfig']
   subprocess.check_call(install_cmd)
-  print(' Cleaning %s...' % basename)
+  print((' Cleaning %s...' % basename))
   subprocess.check_call(['rm', '-rf', basename])
 
 def package(manifest, pkg, target):
@@ -60,9 +61,9 @@ def package(manifest, pkg, target):
 
 def fetch_package(manifest, pkg, host):
   version, info = package(manifest, pkg, host)
-  print('%s %s\n  %s\n  %s' % (pkg, version, info['url'], info['hash']))
+  print(('%s %s\n  %s\n  %s' % (pkg, version, info['url'], info['hash'])))
   if not info['available']:
-    print('%s marked unavailable for %s' % (pkg, host))
+    print(('%s marked unavailable for %s' % (pkg, host)))
     raise AssertionError
   fetch(info['url'])
   return info
@@ -84,15 +85,15 @@ def tar_for_host(host):
   return tar_options, tar_ext
 
 def repack(host, targets, channel='stable', suffix=''):
-  print("Repacking rust for %s..." % host)
+  print(("Repacking rust for %s..." % host))
   url = 'https://static.rust-lang.org/dist/channel-rust-' + channel + '.toml'
   req = requests.get(url)
   req.raise_for_status()
   manifest = toml.loads(req.content)
   if manifest['manifest-version'] != '2':
-    print('ERROR: unrecognized manifest version %s.' % manifest['manifest-version'])
+    print(('ERROR: unrecognized manifest version %s.' % manifest['manifest-version']))
     return
-  print('Using manifest for rust %s as of %s.' % (channel, manifest['date']))
+  print(('Using manifest for rust %s as of %s.' % (channel, manifest['date'])))
   print('Fetching packages...')
   rustc = fetch_package(manifest, 'rustc', host)
   cargo = fetch_package(manifest, 'cargo', host)
@@ -109,13 +110,13 @@ def repack(host, targets, channel='stable', suffix=''):
   for std in stds:
     install(os.path.basename(std['url']), install_dir)
     pass
-  print('Tarring %s...' % tar_basename)
+  print(('Tarring %s...' % tar_basename))
   tar_options, tar_ext = tar_for_host(host)
   subprocess.check_call(['tar', tar_options, tar_basename + tar_ext, install_dir])
   subprocess.check_call(['rm', '-rf', install_dir])
 
 def repack_cargo(host, channel='nightly'):
-  print("Repacking cargo for %s..." % host)
+  print(("Repacking cargo for %s..." % host))
   # Cargo doesn't seem to have a .toml manifest.
   base_url = 'https://static.rust-lang.org/cargo-dist/'
   req = requests.get(os.path.join(base_url, 'channel-cargo-' + channel))
@@ -125,7 +126,7 @@ def repack_cargo(host, channel='nightly'):
       if line.find(host) != -1:
           file = line.strip()
   if not file:
-      print('No manifest entry for %s!' % host)
+      print(('No manifest entry for %s!' % host))
       return
   manifest = {
           'date': req.headers['Last-Modified'],
@@ -142,7 +143,7 @@ def repack_cargo(host, channel='nightly'):
               },
           },
   }
-  print('Using manifest for cargo %s.' % channel)
+  print(('Using manifest for cargo %s.' % channel))
   print('Fetching packages...')
   cargo = fetch_package(manifest, 'cargo', host)
   print('Installing packages...')
@@ -150,7 +151,7 @@ def repack_cargo(host, channel='nightly'):
   subprocess.check_call(['rm', '-rf', install_dir])
   install(os.path.basename(cargo['url']), install_dir)
   tar_basename = 'cargo-%s-repack' % host
-  print('Tarring %s...' % tar_basename)
+  print(('Tarring %s...' % tar_basename))
   tar_options, tar_ext = tar_for_host(host)
   subprocess.check_call(['tar', tar_options, tar_basename + tar_ext, install_dir])
   subprocess.check_call(['rm', '-rf', install_dir])
diff --git a/testing/docker/rust-build/tcbuild.py b/testing/docker/rust-build/tcbuild.py
index d55c6f3a75..cf76482858 100644
--- a/testing/docker/rust-build/tcbuild.py
+++ b/testing/docker/rust-build/tcbuild.py
@@ -35,7 +35,7 @@ def read_tc_auth(tc_auth_file):
 
 def fill_template_dict(d, keys):
     for key, val in d.items():
-        if isinstance(val, basestring) and '{' in val:
+        if isinstance(val, str) and '{' in val:
             d[key] = val.format(**keys)
         elif isinstance(val, dict):
             fill_template_dict(val, keys)
diff --git a/testing/gtest/rungtests.py b/testing/gtest/rungtests.py
index 4999086800..e60d8d1fd7 100644
--- a/testing/gtest/rungtests.py
+++ b/testing/gtest/rungtests.py
@@ -6,6 +6,7 @@
 
 from __future__ import with_statement
 
+from __future__ import print_function
 from optparse import OptionParser
 import os
 import sys
@@ -172,13 +173,13 @@ def main():
     parser = gtestOptions()
     options, args = parser.parse_args()
     if not args:
-        print >>sys.stderr, """Usage: %s <binary>""" % sys.argv[0]
+        print("""Usage: %s <binary>""" % sys.argv[0], file=sys.stderr)
         sys.exit(1)
     if not options.xre_path:
-        print >>sys.stderr, """Error: --xre-path is required"""
+        print("""Error: --xre-path is required""", file=sys.stderr)
         sys.exit(1)
     if not options.utility_path:
-        print >>sys.stderr, """Warning: --utility-path is required to process assertion stacks"""
+        print("""Warning: --utility-path is required to process assertion stacks""", file=sys.stderr)
 
     update_mozinfo()
     prog = os.path.abspath(args[0])
@@ -189,7 +190,7 @@ def main():
                                   options.cwd,
                                   symbols_path=options.symbols_path,
                                   utility_path=options.utility_path)
-    except Exception, e:
+    except Exception as e:
         log.error(str(e))
         result = False
     sys.exit(0 if result else 1)
diff --git a/testing/mach_commands.py b/testing/mach_commands.py
index a744b0c44f..37090bb728 100644
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -482,13 +482,13 @@ class PushToTry(MachCommandBase):
         rv = defaultdict(list)
         for item in items:
             parsed = parse_arg(item)
-            for key, values in parsed.iteritems():
+            for key, values in parsed.items():
                 rv[key].extend(values)
 
         if not allow_subitems:
-            if not all(item == [] for item in rv.itervalues()):
+            if not all(item == [] for item in rv.values()):
                 raise ValueError("Unexpected subitems in argument")
-            return rv.keys()
+            return list(rv.keys())
         else:
             return rv
 
@@ -616,7 +616,7 @@ class PushToTry(MachCommandBase):
                 print("No saved configuration called %s found in autotry.ini" % kwargs["load"],
                       file=sys.stderr)
 
-            for key, value in kwargs.iteritems():
+            for key, value in kwargs.items():
                 if value in (None, []) and key in defaults:
                     kwargs[key] = defaults[key]
 
@@ -653,7 +653,7 @@ class PushToTry(MachCommandBase):
 
         if kwargs["verbose"] and paths_by_flavor:
             print('The following tests will be selected: ')
-            for flavor, paths in paths_by_flavor.iteritems():
+            for flavor, paths in paths_by_flavor.items():
                 print("%s: %s" % (flavor, ",".join(paths)))
 
         if kwargs["verbose"] or not kwargs["push"]:
diff --git a/testing/mochitest/mach_commands.py b/testing/mochitest/mach_commands.py
index a667c05488..51ca667d32 100644
--- a/testing/mochitest/mach_commands.py
+++ b/testing/mochitest/mach_commands.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, unicode_literals
 
+from __future__ import print_function
 from argparse import Namespace
 from collections import defaultdict
 from itertools import chain
@@ -305,14 +306,14 @@ class MachCommands(MachCommandBase):
 
         flavors = None
         if flavor:
-            for fname, fobj in ALL_FLAVORS.iteritems():
+            for fname, fobj in ALL_FLAVORS.items():
                 if flavor in fobj['aliases']:
                     if buildapp not in fobj['enabled_apps']:
                         continue
                     flavors = [fname]
                     break
         else:
-            flavors = [f for f, v in ALL_FLAVORS.iteritems() if buildapp in v['enabled_apps']]
+            flavors = [f for f, v in ALL_FLAVORS.items() if buildapp in v['enabled_apps']]
 
         from mozbuild.controller.building import BuildDriver
         self._ensure_state_subdir_exists('.')
@@ -376,8 +377,8 @@ class MachCommands(MachCommandBase):
         if not suites:
             # Make it very clear why no tests were found
             if not unsupported:
-                print(TESTS_NOT_FOUND.format('\n'.join(
-                    sorted(list(test_paths or test_objects)))))
+                print((TESTS_NOT_FOUND.format('\n'.join(
+                    sorted(list(test_paths or test_objects))))))
                 return 1
 
             msg = []
@@ -393,8 +394,8 @@ class MachCommands(MachCommandBase):
                 else:
                     reason = 'excluded by the command line'
                 msg.append('    mochitest -f {} ({})'.format(name, reason))
-            print(SUPPORTED_TESTS_NOT_FOUND.format(
-                buildapp, '\n'.join(sorted(msg))))
+            print((SUPPORTED_TESTS_NOT_FOUND.format(
+                buildapp, '\n'.join(sorted(msg)))))
             return 1
 
         if buildapp == 'android':
@@ -410,7 +411,7 @@ class MachCommands(MachCommandBase):
             msg = fobj['aliases'][0]
             if subsuite:
                 msg = '{} with subsuite {}'.format(msg, subsuite)
-            print(NOW_RUNNING.format(msg))
+            print((NOW_RUNNING.format(msg)))
 
             harness_args = kwargs.copy()
             harness_args['subsuite'] = subsuite
diff --git a/testing/mochitest/mach_test_package_commands.py b/testing/mochitest/mach_test_package_commands.py
index 01e0167e1d..91a2a3182d 100644
--- a/testing/mochitest/mach_test_package_commands.py
+++ b/testing/mochitest/mach_test_package_commands.py
@@ -25,7 +25,7 @@ def run_mochitest(context, **kwargs):
     if args.test_paths:
         test_root = os.path.join(context.package_root, 'mochitest', 'tests')
         normalize = partial(context.normalize_test_path, test_root)
-        args.test_paths = map(normalize, args.test_paths)
+        args.test_paths = list(map(normalize, args.test_paths))
 
     import mozinfo
     return run_mochitest_desktop(context, args)
diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py
index 796a29b0dc..555cebdabe 100644
--- a/testing/mochitest/mochitest_options.py
+++ b/testing/mochitest/mochitest_options.py
@@ -5,7 +5,7 @@
 from abc import ABCMeta, abstractmethod, abstractproperty
 from argparse import ArgumentParser, SUPPRESS
 from distutils.util import strtobool
-from urlparse import urlparse
+from urllib.parse import urlparse
 import json
 import os
 import tempfile
@@ -15,6 +15,7 @@ from mozprofile import DEFAULT_PORTS
 import mozinfo
 import mozlog
 import moznetwork
+import six
 
 
 here = os.path.abspath(os.path.dirname(__file__))
@@ -63,9 +64,7 @@ def get_default_valgrind_suppression_files():
     return rv
 
 
-class ArgumentContainer():
-    __metaclass__ = ABCMeta
-
+class ArgumentContainer(six.with_metaclass(ABCMeta)):
     @abstractproperty
     def args(self):
         pass
@@ -982,7 +981,7 @@ class MochitestArgumentParser(ArgumentParser):
 
         if self.app not in container_map:
             self.error("Unrecognized app '{}'! Must be one of: {}".format(
-                self.app, ', '.join(container_map.keys())))
+                self.app, ', '.join(list(container_map.keys()))))
 
         defaults = {}
         for container in self.containers:
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
index 8235666bbb..21a1254ae6 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_base.py
@@ -118,7 +118,7 @@ class StreamBase(object):
                     'Receiving %d byte failed. Peer (%r) closed connection' %
                     (length, (self._request.connection.remote_addr,)))
             return read_bytes
-        except socket.error, e:
+        except socket.error as e:
             # Catch a socket.error. Because it's not a child class of the
             # IOError prior to Python 2.6, we cannot omit this except clause.
             # Use %s rather than %r for the exception to use human friendly
@@ -126,7 +126,7 @@ class StreamBase(object):
             raise ConnectionTerminatedException(
                 'Receiving %d byte failed. socket.error (%s) occurred' %
                 (length, e))
-        except IOError, e:
+        except IOError as e:
             # Also catch an IOError because mod_python throws it.
             raise ConnectionTerminatedException(
                 'Receiving %d byte failed. IOError (%s) occurred' %
@@ -139,7 +139,7 @@ class StreamBase(object):
 
         try:
             self._request.connection.write(bytes_to_write)
-        except Exception, e:
+        except Exception as e:
             util.prepend_message_to_exception(
                     'Failed to send message to %r: ' %
                             (self._request.connection.remote_addr,),
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi.py b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi.py
index 104221b4c3..5ae839e70a 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/_stream_hybi.py
@@ -501,7 +501,7 @@ class Stream(StreamBase):
             raise BadOperationException(
                 'Requested send_message after sending out a closing handshake')
 
-        if binary and isinstance(message, unicode):
+        if binary and isinstance(message, str):
             raise BadOperationException(
                 'Message for binary frame must be instance of str')
 
@@ -538,7 +538,7 @@ class Stream(StreamBase):
                 # at least one frame is sent.
                 if len(message) <= bytes_written:
                     break
-        except ValueError, e:
+        except ValueError as e:
             raise BadOperationException(e)
 
     def _get_message_from_frame(self, frame):
@@ -677,7 +677,7 @@ class Stream(StreamBase):
             if handler:
                 handler(self._request, message)
                 return
-        except AttributeError, e:
+        except AttributeError as e:
             pass
         self._send_pong(message)
 
@@ -704,7 +704,7 @@ class Stream(StreamBase):
                     break
                 else:
                     inflight_pings.append(expected_body)
-            except IndexError, e:
+            except IndexError as e:
                 # The received pong was unsolicited pong. Keep the
                 # ping queue as is.
                 self._ping_queue = inflight_pings
@@ -715,7 +715,7 @@ class Stream(StreamBase):
             handler = self._request.on_pong_handler
             if handler:
                 handler(self._request, message)
-        except AttributeError, e:
+        except AttributeError as e:
             pass
 
     def receive_message(self):
@@ -780,7 +780,7 @@ class Stream(StreamBase):
                 # CHARACTER.
                 try:
                     return message.decode('utf-8')
-                except UnicodeDecodeError, e:
+                except UnicodeDecodeError as e:
                     raise InvalidUTF8Exception(e)
             elif self._original_opcode == common.OPCODE_BINARY:
                 return message
@@ -837,7 +837,7 @@ class Stream(StreamBase):
                     'close reason must not be specified if code is None')
             reason = ''
         else:
-            if not isinstance(reason, str) and not isinstance(reason, unicode):
+            if not isinstance(reason, str) and not isinstance(reason, str):
                 raise BadOperationException(
                     'close reason must be an instance of str or unicode')
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/common.py b/testing/mochitest/pywebsocket/mod_pywebsocket/common.py
index 8c15242841..f80734c48c 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/common.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/common.py
@@ -233,7 +233,7 @@ def _parse_extension(state):
 
         try:
             _parse_extension_param(state, extension)
-        except ExtensionParsingException, e:
+        except ExtensionParsingException as e:
             raise ExtensionParsingException(
                 'Failed to parse parameter for %r (%r)' %
                 (extension_token, e))
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
index 96c91e0c90..2591fe8b9e 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/dispatch.py
@@ -143,7 +143,7 @@ def _source_handler_file(handler_definition):
 
     global_dic = {}
     try:
-        exec handler_definition in global_dic
+        exec(handler_definition, global_dic)
     except Exception:
         raise DispatchException('Error in sourcing handler:' +
                                 util.get_stack_trace())
@@ -254,12 +254,12 @@ class Dispatcher(object):
         do_extra_handshake_ = handler_suite.do_extra_handshake
         try:
             do_extra_handshake_(request)
-        except handshake.AbortedByUserException, e:
+        except handshake.AbortedByUserException as e:
             # Re-raise to tell the caller of this function to finish this
             # connection without sending any error.
             self._logger.debug('%s', util.get_stack_trace())
             raise
-        except Exception, e:
+        except Exception as e:
             util.prepend_message_to_exception(
                     '%s raised exception for %s: ' % (
                             _DO_EXTRA_HANDSHAKE_HANDLER_NAME,
@@ -296,28 +296,28 @@ class Dispatcher(object):
             if not request.server_terminated:
                 request.ws_stream.close_connection()
         # Catch non-critical exceptions the handler didn't handle.
-        except handshake.AbortedByUserException, e:
+        except handshake.AbortedByUserException as e:
             self._logger.debug('%s', util.get_stack_trace())
             raise
-        except msgutil.BadOperationException, e:
+        except msgutil.BadOperationException as e:
             self._logger.debug('%s', e)
             request.ws_stream.close_connection(
                 common.STATUS_INTERNAL_ENDPOINT_ERROR)
-        except msgutil.InvalidFrameException, e:
+        except msgutil.InvalidFrameException as e:
             # InvalidFrameException must be caught before
             # ConnectionTerminatedException that catches InvalidFrameException.
             self._logger.debug('%s', e)
             request.ws_stream.close_connection(common.STATUS_PROTOCOL_ERROR)
-        except msgutil.UnsupportedFrameException, e:
+        except msgutil.UnsupportedFrameException as e:
             self._logger.debug('%s', e)
             request.ws_stream.close_connection(common.STATUS_UNSUPPORTED_DATA)
-        except stream.InvalidUTF8Exception, e:
+        except stream.InvalidUTF8Exception as e:
             self._logger.debug('%s', e)
             request.ws_stream.close_connection(
                 common.STATUS_INVALID_FRAME_PAYLOAD_DATA)
-        except msgutil.ConnectionTerminatedException, e:
+        except msgutil.ConnectionTerminatedException as e:
             self._logger.debug('%s', e)
-        except Exception, e:
+        except Exception as e:
             # Any other exceptions are forwarded to the caller of this
             # function.
             util.prepend_message_to_exception(
@@ -379,7 +379,7 @@ class Dispatcher(object):
                 continue
             try:
                 handler_suite = _source_handler_file(open(path).read())
-            except DispatchException, e:
+            except DispatchException as e:
                 self._source_warnings.append('%s: %s' % (path, e))
                 continue
             resource = convert(path)
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/extensions.py b/testing/mochitest/pywebsocket/mod_pywebsocket/extensions.py
index 1edd988f61..6ab90ce1ae 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/extensions.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/extensions.py
@@ -185,7 +185,7 @@ class DeflateFrameExtensionProcessor(ExtensionProcessorInterface):
                 self._WINDOW_BITS_PARAM)
             try:
                 window_bits = _parse_window_bits(window_bits)
-            except ValueError, e:
+            except ValueError as e:
                 return None
 
         no_context_takeover = self._request.has_parameter(
@@ -381,7 +381,7 @@ class PerMessageDeflateExtensionProcessor(ExtensionProcessorInterface):
             try:
                 server_max_window_bits = _parse_window_bits(
                     server_max_window_bits)
-            except ValueError, e:
+            except ValueError as e:
                 self._logger.debug('Bad %s parameter: %r',
                                    self._SERVER_MAX_WINDOW_BITS_PARAM,
                                    e)
@@ -717,7 +717,7 @@ class MuxExtensionProcessor(ExtensionProcessorInterface):
         if quota is not None:
             try:
                 quota = int(quota)
-            except ValueError, e:
+            except ValueError as e:
                 return None
             if quota < 0 or quota >= 2 ** 32:
                 return None
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
index 194f6b395a..707263a69f 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/__init__.py
@@ -90,15 +90,15 @@ def do_handshake(request, dispatcher, allowDraft75=False, strict=False):
             handshaker.do_handshake()
             _LOGGER.info('Established (%s protocol)', name)
             return
-        except HandshakeException, e:
+        except HandshakeException as e:
             _LOGGER.debug(
                 'Failed to complete opening handshake as %s protocol: %r',
                 name, e)
             if e.status:
                 raise e
-        except AbortedByUserException, e:
+        except AbortedByUserException as e:
             raise
-        except VersionException, e:
+        except VersionException as e:
             raise
 
     # TODO(toyoshim): Add a test to cover the case all handshakers fail.
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
index c993a584b7..0af05242bf 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/_base.py
@@ -111,7 +111,7 @@ def parse_host_header(request):
         return fields[0], get_default_port(request.is_https())
     try:
         return fields[0], int(fields[1])
-    except ValueError, e:
+    except ValueError as e:
         raise HandshakeException('Invalid port number format: %r' % e)
 
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi.py b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi.py
index 44e71f179f..853c928bcb 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/handshake/hybi.py
@@ -112,7 +112,7 @@ class Handshaker(object):
 
         try:
             connection_tokens = parse_token_list(connection)
-        except HandshakeException, e:
+        except HandshakeException as e:
             raise HandshakeException(
                 'Failed to parse %s: %s' % (common.CONNECTION_HEADER, e))
 
@@ -182,8 +182,7 @@ class Handshaker(object):
 
             # Extra handshake handler may modify/remove processors.
             self._dispatcher.do_extra_handshake(self._request)
-            processors = filter(lambda processor: processor is not None,
-                                self._request.ws_extension_processors)
+            processors = [processor for processor in self._request.ws_extension_processors if processor is not None]
 
             # Ask each processor if there are extensions on the request which
             # cannot co-exist. When processor decided other processors cannot
@@ -194,8 +193,7 @@ class Handshaker(object):
                 if processor.is_active():
                     processor.check_consistency_with_other_processors(
                         processors)
-            processors = filter(lambda processor: processor.is_active(),
-                                processors)
+            processors = [processor for processor in processors if processor.is_active()]
 
             accepted_extensions = []
 
@@ -220,8 +218,7 @@ class Handshaker(object):
                 self._request.mux_processor = processors[mux_index]
                 self._request.mux_processor.set_extensions(
                     logical_channel_extensions)
-                processors = filter(lambda processor: processor.is_active(),
-                                    processors)
+                processors = [processor for processor in processors if processor.is_active()]
 
             stream_options = StreamOptions()
 
@@ -242,7 +239,7 @@ class Handshaker(object):
                     continue
 
                 # Inactivate all of the following compression extensions.
-                for j in xrange(index + 1, len(processors)):
+                for j in range(index + 1, len(processors)):
                     if is_compression_extension(processors[j].name()):
                         processors[j].set_active(False)
 
@@ -250,7 +247,7 @@ class Handshaker(object):
                 self._request.ws_extensions = accepted_extensions
                 self._logger.debug(
                     'Extensions accepted: %r',
-                    map(common.ExtensionParameter.name, accepted_extensions))
+                    list(map(common.ExtensionParameter.name, accepted_extensions)))
             else:
                 self._request.ws_extensions = None
 
@@ -273,7 +270,7 @@ class Handshaker(object):
                         'request any subprotocol')
 
             self._send_handshake(accept)
-        except HandshakeException, e:
+        except HandshakeException as e:
             if not e.status:
                 # Fallback to 400 bad request by default.
                 e.status = common.HTTP_STATUS_BAD_REQUEST
@@ -330,14 +327,14 @@ class Handshaker(object):
         try:
             self._request.ws_requested_extensions = common.parse_extensions(
                 extensions_header)
-        except common.ExtensionParsingException, e:
+        except common.ExtensionParsingException as e:
             raise HandshakeException(
                 'Failed to parse Sec-WebSocket-Extensions header: %r' % e)
 
         self._logger.debug(
             'Extensions requested: %r',
-            map(common.ExtensionParameter.name,
-                self._request.ws_requested_extensions))
+            list(map(common.ExtensionParameter.name,
+                self._request.ws_requested_extensions)))
 
     def _validate_key(self, key):
         if key.find(',') >= 0:
@@ -356,7 +353,7 @@ class Handshaker(object):
                 decoded_key = base64.b64decode(key)
                 if len(decoded_key) == 16:
                     key_is_valid = True
-        except TypeError, e:
+        except TypeError as e:
             pass
 
         if not key_is_valid:
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py b/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
index c244421cf7..bfee5c3359 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/headerparserhandler.py
@@ -199,7 +199,7 @@ def headerparserhandler(request):
             request.log_error(
                 'mod_pywebsocket: Fallback to Apache', apache.APLOG_INFO)
             return apache.DECLINED
-    except dispatch.DispatchException, e:
+    except dispatch.DispatchException as e:
         request.log_error(
             'mod_pywebsocket: Dispatch failed for error: %s' % e,
             apache.APLOG_INFO)
@@ -215,14 +215,14 @@ def headerparserhandler(request):
         try:
             handshake.do_handshake(
                 request, _dispatcher, allowDraft75=allow_draft75)
-        except handshake.VersionException, e:
+        except handshake.VersionException as e:
             request.log_error(
                 'mod_pywebsocket: Handshake failed for version error: %s' % e,
                 apache.APLOG_INFO)
             request.err_headers_out.add(common.SEC_WEBSOCKET_VERSION_HEADER,
                                         e.supported_versions)
             return apache.HTTP_BAD_REQUEST
-        except handshake.HandshakeException, e:
+        except handshake.HandshakeException as e:
             # Handshake for ws/wss failed.
             # Send http response with error status.
             request.log_error(
@@ -233,9 +233,9 @@ def headerparserhandler(request):
         handshake_is_done = True
         request._dispatcher = _dispatcher
         _dispatcher.transfer_data(request)
-    except handshake.AbortedByUserException, e:
+    except handshake.AbortedByUserException as e:
         request.log_error('mod_pywebsocket: Aborted: %s' % e, apache.APLOG_INFO)
-    except Exception, e:
+    except Exception as e:
         # DispatchException can also be thrown if something is wrong in
         # pywebsocket code. It's caught here, then.
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/http_header_util.py b/testing/mochitest/pywebsocket/mod_pywebsocket/http_header_util.py
index b774653932..0afa19c087 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/http_header_util.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/http_header_util.py
@@ -33,7 +33,7 @@ in HTTP RFC http://www.ietf.org/rfc/rfc2616.txt.
 """
 
 
-import urlparse
+import six.moves.urllib.parse
 
 
 _SEPARATORS = '()<>@,;:\\"/[]?={} \t'
@@ -218,7 +218,7 @@ def quote_if_necessary(s):
 def parse_uri(uri):
     """Parse absolute URI then return host, port and resource."""
 
-    parsed = urlparse.urlsplit(uri)
+    parsed = six.moves.urllib.parse.urlsplit(uri)
     if parsed.scheme != 'wss' and parsed.scheme != 'ws':
         # |uri| must be a relative URI.
         # TODO(toyoshim): Should validate |uri|.
@@ -230,7 +230,7 @@ def parse_uri(uri):
     port = None
     try:
         port = parsed.port
-    except ValueError, e:
+    except ValueError as e:
         # port property cause ValueError on invalid null port description like
         # 'ws://host:/path'.
         return None, None, None
@@ -253,11 +253,11 @@ def parse_uri(uri):
 
 
 try:
-    urlparse.uses_netloc.index('ws')
-except ValueError, e:
+    six.moves.urllib.parse.uses_netloc.index('ws')
+except ValueError as e:
     # urlparse in Python2.5.1 doesn't have 'ws' and 'wss' entries.
-    urlparse.uses_netloc.append('ws')
-    urlparse.uses_netloc.append('wss')
+    six.moves.urllib.parse.uses_netloc.append('ws')
+    six.moves.urllib.parse.uses_netloc.append('wss')
 
 
 # vi:sts=4 sw=4 et
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py b/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
index 4d4cd95859..e2b4a3eb75 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/memorizingfile.py
@@ -47,14 +47,14 @@ class MemorizingFile(object):
     the control reaches WebSocketRequestHandler.
     """
 
-    def __init__(self, file_, max_memorized_lines=sys.maxint):
+    def __init__(self, file_, max_memorized_lines=sys.maxsize):
         """Construct an instance.
 
         Args:
             file_: the file object to wrap.
             max_memorized_lines: the maximum number of lines to memorize.
                 Only the first max_memorized_lines are memorized.
-                Default: sys.maxint.
+                Default: sys.maxsize.
         """
 
         self._file = file_
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py b/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
index 4c1a0114b4..22a7013cd0 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/msgutil.py
@@ -38,7 +38,7 @@ bytes writing/reading.
 """
 
 
-import Queue
+import six.moves.queue
 import threading
 
 
@@ -124,7 +124,7 @@ class MessageReceiver(threading.Thread):
 
         threading.Thread.__init__(self)
         self._request = request
-        self._queue = Queue.Queue()
+        self._queue = six.moves.queue.Queue()
         self._onmessage = onmessage
         self._stop_requested = False
         self.setDaemon(True)
@@ -157,7 +157,7 @@ class MessageReceiver(threading.Thread):
         """
         try:
             message = self._queue.get_nowait()
-        except Queue.Empty:
+        except six.moves.queue.Empty:
             message = None
         return message
 
@@ -190,7 +190,7 @@ class MessageSender(threading.Thread):
         """
         threading.Thread.__init__(self)
         self._request = request
-        self._queue = Queue.Queue()
+        self._queue = six.moves.queue.Queue()
         self.setDaemon(True)
         self.start()
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/mux.py b/testing/mochitest/pywebsocket/mod_pywebsocket/mux.py
index 76334685b3..bc508e7dc6 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/mux.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/mux.py
@@ -353,7 +353,7 @@ class _MuxFramePayloadParser(object):
 
         try:
             size = self._read_number()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
                                           str(e))
         pos = self._read_position
@@ -376,7 +376,7 @@ class _MuxFramePayloadParser(object):
         encoding = first_byte & 0x3
         try:
             control_block.channel_id = self.read_channel_id()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK)
         control_block.encoding = encoding
         encoded_handshake = self._read_size_and_contents()
@@ -394,7 +394,7 @@ class _MuxFramePayloadParser(object):
         control_block.encoding = first_byte & 0x3
         try:
             control_block.channel_id = self.read_channel_id()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK)
         control_block.encoded_handshake = self._read_size_and_contents()
         return control_block
@@ -409,7 +409,7 @@ class _MuxFramePayloadParser(object):
         try:
             control_block.channel_id = self.read_channel_id()
             control_block.send_quota = self._read_number()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
                                           str(e))
 
@@ -424,7 +424,7 @@ class _MuxFramePayloadParser(object):
 
         try:
             control_block.channel_id = self.read_channel_id()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK)
         reason = self._read_size_and_contents()
         if len(reason) == 0:
@@ -449,7 +449,7 @@ class _MuxFramePayloadParser(object):
         try:
             control_block.slots = self._read_number()
             control_block.send_quota = self._read_number()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_INVALID_MUX_CONTROL_BLOCK,
                                           str(e))
         return control_block
@@ -921,7 +921,7 @@ class _LogicalStream(Stream):
 
                 opcode = common.OPCODE_CONTINUATION
 
-        except ValueError, e:
+        except ValueError as e:
             raise BadOperationException(e)
         finally:
             self._write_inner_frame_semaphore.release()
@@ -960,7 +960,7 @@ class _LogicalStream(Stream):
             raise BadOperationException(
                 'Requested send_message after sending out a closing handshake')
 
-        if binary and isinstance(message, unicode):
+        if binary and isinstance(message, str):
             raise BadOperationException(
                 'Message for binary frame must be instance of str')
 
@@ -1029,7 +1029,7 @@ class _LogicalStream(Stream):
         # connection has closed gracefully.
         try:
             return Stream.receive_message(self)
-        except LogicalConnectionClosedException, e:
+        except LogicalConnectionClosedException as e:
             self._logger.debug('%s', e)
             return None
 
@@ -1144,7 +1144,7 @@ class _PhysicalConnectionWriter(threading.Thread):
         try:
             self._mux_handler.physical_stream.send_message(
                 message=message, end=True, binary=True)
-        except Exception, e:
+        except Exception as e:
             util.prepend_message_to_exception(
                 'Failed to send message to %r: ' %
                 (self._mux_handler.physical_connection.remote_addr,), e)
@@ -1185,7 +1185,7 @@ class _PhysicalConnectionWriter(threading.Thread):
                 # by the reader thread.
                 self._mux_handler.physical_stream.close_connection(
                     self._close_code, wait_response=False)
-            except Exception, e:
+            except Exception as e:
                 util.prepend_message_to_exception(
                     'Failed to close the physical connection: %r' % e)
                 raise
@@ -1233,20 +1233,20 @@ class _PhysicalConnectionReader(threading.Thread):
                         'Received a text message on physical connection')
                     break
 
-            except ConnectionTerminatedException, e:
+            except ConnectionTerminatedException as e:
                 self._logger.debug('%s', e)
                 break
 
             try:
                 self._mux_handler.dispatch_message(message)
-            except PhysicalConnectionError, e:
+            except PhysicalConnectionError as e:
                 self._mux_handler.fail_physical_connection(
                     e.drop_code, e.message)
                 break
-            except LogicalChannelError, e:
+            except LogicalChannelError as e:
                 self._mux_handler.fail_logical_channel(
                     e.channel_id, e.drop_code, e.message)
-            except Exception, e:
+            except Exception as e:
                 self._logger.debug(traceback.format_exc())
                 break
 
@@ -1278,7 +1278,7 @@ class _Worker(threading.Thread):
         try:
             # Non-critical exceptions will be handled by dispatcher.
             self._mux_handler.dispatcher.transfer_data(self._request)
-        except LogicalChannelError, e:
+        except LogicalChannelError as e:
             self._mux_handler.fail_logical_channel(
                 e.channel_id, e.drop_code, e.message)
         finally:
@@ -1392,7 +1392,7 @@ class _HandshakeDeltaBase(object):
             for key, value in delta.items():
                 # The spec requires that a header with an empty value is
                 # removed from the delta base.
-                if len(value) == 0 and headers.has_key(key):
+                if len(value) == 0 and key in headers:
                     del headers[key]
                 else:
                     headers[key] = value
@@ -1621,19 +1621,19 @@ class _MuxHandler(object):
                                     send_quota, receive_quota)
         try:
             handshaker.do_handshake()
-        except handshake.VersionException, e:
+        except handshake.VersionException as e:
             self._logger.info('%s', e)
             self._send_error_add_channel_response(
                 request.channel_id, status=common.HTTP_STATUS_BAD_REQUEST)
             return False
-        except handshake.HandshakeException, e:
+        except handshake.HandshakeException as e:
             # TODO(bashi): Should we _Fail the Logical Channel_ with 3001
             # instead?
             self._logger.info('%s', e)
             self._send_error_add_channel_response(request.channel_id,
                                                   status=e.status)
             return False
-        except handshake.AbortedByUserException, e:
+        except handshake.AbortedByUserException as e:
             self._logger.info('%s', e)
             self._send_error_add_channel_response(request.channel_id)
             return False
@@ -1660,7 +1660,7 @@ class _MuxHandler(object):
     def _process_add_channel_request(self, block):
         try:
             logical_request = self._create_logical_request(block)
-        except ValueError, e:
+        except ValueError as e:
             self._logger.debug('Failed to create logical request: %r' % e)
             self._send_error_add_channel_response(
                 block.channel_id, status=common.HTTP_STATUS_BAD_REQUEST)
@@ -1767,7 +1767,7 @@ class _MuxHandler(object):
         parser = _MuxFramePayloadParser(message)
         try:
             channel_id = parser.read_channel_id()
-        except ValueError, e:
+        except ValueError as e:
             raise PhysicalConnectionError(_DROP_CODE_CHANNEL_ID_TRUNCATED)
         if channel_id == _CONTROL_CHANNEL_ID:
             self._process_control_blocks(parser)
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/util.py b/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
index d224ae3942..726c7339b7 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/util.py
@@ -147,7 +147,7 @@ def wrap_popen3_for_win(cygwin_path):
 
 
 def hexify(s):
-    return ' '.join(map(lambda x: '%02x' % ord(x), s))
+    return ' '.join(['%02x' % ord(x) for x in s])
 
 
 def get_class_logger(o):
@@ -191,11 +191,11 @@ class RepeatedXorMasker(object):
 
         # Use temporary local variables to eliminate the cost to access
         # attributes
-        masking_key = map(ord, self._masking_key)
+        masking_key = list(map(ord, self._masking_key))
         masking_key_size = len(masking_key)
         masking_key_index = self._masking_key_index
 
-        for i in xrange(len(result)):
+        for i in range(len(result)):
             result[i] ^= masking_key[masking_key_index]
             masking_key_index = (masking_key_index + 1) % masking_key_size
 
diff --git a/testing/mochitest/pywebsocket/mod_pywebsocket/xhr_benchmark_handler.py b/testing/mochitest/pywebsocket/mod_pywebsocket/xhr_benchmark_handler.py
index 6735c7e2a3..dd227a410b 100644
--- a/testing/mochitest/pywebsocket/mod_pywebsocket/xhr_benchmark_handler.py
+++ b/testing/mochitest/pywebsocket/mod_pywebsocket/xhr_benchmark_handler.py
@@ -60,7 +60,7 @@ class XHRBenchmarkHandler(object):
         bytes_to_send = request_array[0]
         try:
             bytes_to_send = int(bytes_to_send)
-        except ValueError, e:
+        except ValueError as e:
             self._logger.debug('Malformed size parameter: %r', bytes_to_send)
             return
         self._logger.debug('Requested to send %s bytes', bytes_to_send)
diff --git a/testing/mochitest/pywebsocket/standalone.py b/testing/mochitest/pywebsocket/standalone.py
index e176327439..56cc8c1265 100755
--- a/testing/mochitest/pywebsocket/standalone.py
+++ b/testing/mochitest/pywebsocket/standalone.py
@@ -155,13 +155,13 @@ It may execute arbitrary Python code or external programs. It should not be
 used outside a firewall.
 """
 
-import BaseHTTPServer
-import CGIHTTPServer
-import SimpleHTTPServer
-import SocketServer
-import ConfigParser
+import six.moves.BaseHTTPServer
+import six.moves.CGIHTTPServer
+import six.moves.SimpleHTTPServer
+import six.moves.socketserver
+import six.moves.configparser
 import base64
-import httplib
+import six.moves.http_client
 import logging
 import logging.handlers
 import optparse
@@ -347,7 +347,8 @@ class _StandaloneSSLConnection(object):
 
         try:
             return self._connection.recv(bufsize)
-        except OpenSSL.SSL.SysCallError, (err, message):
+        except OpenSSL.SSL.SysCallError as xxx_todo_changeme:
+            (err, message) = xxx_todo_changeme.args
             if err == -1:
                 # Suppress "unexpected EOF" exception. See the OpenSSL document
                 # for SSL_get_error.
@@ -375,13 +376,13 @@ def _alias_handlers(dispatcher, websock_handlers_map_file):
             try:
                 dispatcher.add_resource_path_alias(
                     m.group(1), m.group(2))
-            except dispatch.DispatchException, e:
+            except dispatch.DispatchException as e:
                 logging.error(str(e))
     finally:
         fp.close()
 
 
-class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+class WebSocketServer(six.moves.socketserver.ThreadingMixIn, six.moves.BaseHTTPServer.HTTPServer):
     """HTTPServer specialized for WebSocket."""
 
     # Overrides SocketServer.ThreadingMixIn.daemon_threads
@@ -415,7 +416,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
         self.__ws_is_shut_down = threading.Event()
         self.__ws_serving = False
 
-        SocketServer.BaseServer.__init__(
+        six.moves.socketserver.BaseServer.__init__(
             self, (options.server_host, options.port), WebSocketRequestHandler)
 
         # Expose the options object to allow handler objects access it. We name
@@ -451,7 +452,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
             family, socktype, proto, canonname, sockaddr = addrinfo
             try:
                 socket_ = socket.socket(family, socktype)
-            except Exception, e:
+            except Exception as e:
                 self._logger.info('Skip by failure: %r', e)
                 continue
             server_options = self.websocket_server_options
@@ -489,7 +490,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
                 socket_.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
             try:
                 socket_.bind(self.server_address)
-            except Exception, e:
+            except Exception as e:
                 self._logger.info('Skip by failure: %r', e)
                 socket_.close()
                 failed_sockets.append(socketinfo)
@@ -518,7 +519,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
             self._logger.info('Listen on: %r', addrinfo)
             try:
                 socket_.listen(self.request_queue_size)
-            except Exception, e:
+            except Exception as e:
                 self._logger.info('Skip by failure: %r', e)
                 socket_.close()
                 failed_sockets.append(socketinfo)
@@ -569,7 +570,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
             if server_options.tls_module == _TLS_BY_STANDARD_MODULE:
                 try:
                     accepted_socket.do_handshake()
-                except ssl.SSLError, e:
+                except ssl.SSLError as e:
                     self._logger.debug('%r', e)
                     raise
 
@@ -608,7 +609,7 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
                 # TODO(tyoshino): Convert all kinds of errors.
                 try:
                     accepted_socket.do_handshake()
-                except OpenSSL.SSL.Error, e:
+                except OpenSSL.SSL.Error as e:
                     # Set errno part to 1 (SSL_ERROR_SSL) like the ssl module
                     # does.
                     self._logger.debug('%r', e)
@@ -652,11 +653,11 @@ class WebSocketServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
         self.__ws_is_shut_down.wait()
 
 
-class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
+class WebSocketRequestHandler(six.moves.CGIHTTPServer.CGIHTTPRequestHandler):
     """CGIHTTPRequestHandler specialized for WebSocket."""
 
     # Use httplib.HTTPMessage instead of mimetools.Message.
-    MessageClass = httplib.HTTPMessage
+    MessageClass = six.moves.http_client.HTTPMessage
 
     def setup(self):
         """Override SocketServer.StreamRequestHandler.setup to wrap rfile
@@ -672,7 +673,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
         # Call superclass's setup to prepare rfile, wfile, etc. See setup
         # definition on the root class SocketServer.StreamRequestHandler to
         # understand what this does.
-        CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
+        six.moves.CGIHTTPServer.CGIHTTPRequestHandler.setup(self)
 
         self.rfile = memorizingfile.MemorizingFile(
             self.rfile,
@@ -690,7 +691,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
             self.is_executable = self._options.is_executable_method
 
         # This actually calls BaseRequestHandler.__init__.
-        CGIHTTPServer.CGIHTTPRequestHandler.__init__(
+        six.moves.CGIHTTPServer.CGIHTTPRequestHandler.__init__(
             self, request, client_address, server)
 
     def parse_request(self):
@@ -711,7 +712,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
         # handling (self.path, self.command, self.requestline, etc. See also
         # how _StandaloneRequest's members are implemented using these
         # attributes).
-        if not CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self):
+        if not six.moves.CGIHTTPServer.CGIHTTPRequestHandler.parse_request(self):
             return False
 
         if self._options.use_basic_auth:
@@ -772,7 +773,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
                                   self.path)
                 self._logger.info('Fallback to CGIHTTPRequestHandler')
                 return True
-        except dispatch.DispatchException, e:
+        except dispatch.DispatchException as e:
             self._logger.info('Dispatch failed for error: %s', e)
             self.send_error(e.status)
             return False
@@ -788,14 +789,14 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
                     self._options.dispatcher,
                     allowDraft75=self._options.allow_draft75,
                     strict=self._options.strict)
-            except handshake.VersionException, e:
+            except handshake.VersionException as e:
                 self._logger.info('Handshake failed for version error: %s', e)
                 self.send_response(common.HTTP_STATUS_BAD_REQUEST)
                 self.send_header(common.SEC_WEBSOCKET_VERSION_HEADER,
                                  e.supported_versions)
                 self.end_headers()
                 return False
-            except handshake.HandshakeException, e:
+            except handshake.HandshakeException as e:
                 # Handshake for ws(s) failed.
                 self._logger.info('Handshake failed for error: %s', e)
                 self.send_error(e.status)
@@ -803,7 +804,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
 
             request._dispatcher = self._options.dispatcher
             self._options.dispatcher.transfer_data(request)
-        except handshake.AbortedByUserException, e:
+        except handshake.AbortedByUserException as e:
             self._logger.info('Aborted: %s', e)
         return False
 
@@ -831,7 +832,7 @@ class WebSocketRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler):
         rather than a CGI script.
         """
 
-        if CGIHTTPServer.CGIHTTPRequestHandler.is_cgi(self):
+        if six.moves.CGIHTTPServer.CGIHTTPRequestHandler.is_cgi(self):
             if '..' in self.path:
                 return False
             # strip query parameter from request path
@@ -1044,14 +1045,14 @@ def _parse_args_and_config(args):
     if temporary_options.config_file:
         try:
             config_fp = open(temporary_options.config_file, 'r')
-        except IOError, e:
+        except IOError as e:
             logging.critical(
                 'Failed to open configuration file %r: %r',
                 temporary_options.config_file,
                 e)
             sys.exit(1)
 
-        config_parser = ConfigParser.SafeConfigParser()
+        config_parser = six.moves.configparser.SafeConfigParser()
         config_parser.readfp(config_fp)
         config_fp.close()
 
@@ -1172,7 +1173,7 @@ def _main(args=None):
 
         server = WebSocketServer(options)
         server.serve_forever()
-    except Exception, e:
+    except Exception as e:
         logging.critical('mod_pywebsocket: %s' % e)
         logging.critical('mod_pywebsocket: %s' % util.get_stack_trace())
         sys.exit(1)
diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py
index 07547dd238..79c1cd53cf 100644
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -7,8 +7,10 @@ Runs the Mochitest test harness.
 """
 
 from __future__ import with_statement
+from __future__ import print_function
 import os
 import sys
+import six
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
 sys.path.insert(0, SCRIPT_DIR)
 
@@ -32,7 +34,7 @@ import sys
 import tempfile
 import time
 import traceback
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import uuid
 import zipfile
 import bisection
@@ -51,7 +53,7 @@ from manifestparser.filters import (
 try:
     from marionette_driver.addons import Addons
     from marionette_harness import Marionette
-except ImportError, e:
+except ImportError as e:
     # Defer ImportError until attempt to use Marionette
     def reraise(*args, **kwargs):
         raise(e)
@@ -63,7 +65,7 @@ from mochitest_options import (
 )
 from mozprofile import Profile, Preferences
 from mozprofile.permissions import ServerLocations
-from urllib import quote_plus as encodeURIComponent
+from urllib.parse import quote_plus as encodeURIComponent
 from mozlog.formatters import TbplFormatter
 from mozlog import commandline
 from mozrunner.utils import get_stack_fixer_function, test_environment
@@ -179,8 +181,8 @@ class MessageLogger(object):
         if 'message' in message:
             if isinstance(message['message'], bytes):
                 message['message'] = message['message'].decode('utf-8', 'replace')
-            elif not isinstance(message['message'], unicode):
-                message['message'] = unicode(message['message'])
+            elif not isinstance(message['message'], str):
+                message['message'] = str(message['message'])
 
     def parse_line(self, line):
         """Takes a given line of input (structured or not) and
@@ -472,7 +474,7 @@ class MochitestServer(object):
 
     def stop(self):
         try:
-            with urllib2.urlopen(self.shutdownURL) as c:
+            with six.moves.urllib.request.urlopen(self.shutdownURL) as c:
                 c.read()
 
             # TODO: need ProcessHandler.poll()
@@ -717,7 +719,7 @@ def findTestMediaDevices(log):
     def sine_source_loaded():
         o = subprocess.check_output(
             ['/usr/bin/pactl', 'list', 'short', 'modules'])
-        return filter(lambda x: 'module-sine-source' in x, o.splitlines())
+        return [x for x in o.splitlines() if 'module-sine-source' in x]
 
     if not sine_source_loaded():
         # Load module-sine-source
@@ -850,7 +852,7 @@ class MochitestDesktop(object):
         try:
             return dict(parseKeyValue(extraPrefs, context='--setpref='))
         except KeyValueParseError as e:
-            print str(e)
+            print(str(e))
             sys.exit(1)
 
     def getFullPath(self, path):
@@ -1448,7 +1450,7 @@ toolbar#nav-bar {
 
         # strip certain unnecessary items to avoid serialization errors in json.dumps()
         d = dict((k, v) for k, v in options.__dict__.items() if (v is None) or
-                 isinstance(v, (basestring, numbers.Number)))
+                 isinstance(v, (str, numbers.Number)))
         d['testRoot'] = self.testRoot
         if options.jscov_dir_prefix:
             d['jscovDirPrefix'] = options.jscov_dir_prefix
@@ -2213,7 +2215,7 @@ toolbar#nav-bar {
 
         result = 1  # default value, if no tests are run.
         for d in dirs:
-            print "dir: %s" % d
+            print("dir: %s" % d)
 
             # BEGIN LEAKCHECK HACK
             # Leak checking was broken in mochitest unnoticed for a length of time. During
@@ -2255,20 +2257,20 @@ toolbar#nav-bar {
 
         # printing total number of tests
         if options.flavor == 'browser':
-            print "TEST-INFO | checking window state"
-            print "Browser Chrome Test Summary"
-            print "\tPassed: %s" % self.countpass
-            print "\tFailed: %s" % self.countfail
-            print "\tTodo: %s" % self.counttodo
-            print "\tMode: %s" % e10s_mode
-            print "*** End BrowserChrome Test Results ***"
+            print("TEST-INFO | checking window state")
+            print("Browser Chrome Test Summary")
+            print("\tPassed: %s" % self.countpass)
+            print("\tFailed: %s" % self.countfail)
+            print("\tTodo: %s" % self.counttodo)
+            print("\tMode: %s" % e10s_mode)
+            print("*** End BrowserChrome Test Results ***")
         else:
-            print "0 INFO TEST-START | Shutdown"
-            print "1 INFO Passed:  %s" % self.countpass
-            print "2 INFO Failed:  %s" % self.countfail
-            print "3 INFO Todo:    %s" % self.counttodo
-            print "4 INFO Mode:    %s" % e10s_mode
-            print "5 INFO SimpleTest FINISHED"
+            print("0 INFO TEST-START | Shutdown")
+            print("1 INFO Passed:  %s" % self.countpass)
+            print("2 INFO Failed:  %s" % self.countfail)
+            print("3 INFO Todo:    %s" % self.counttodo)
+            print("4 INFO Mode:    %s" % e10s_mode)
+            print("5 INFO SimpleTest FINISHED")
 
         return result
 
@@ -2687,7 +2689,7 @@ def run_test_harness(parser, options):
     parser.validate(options)
 
     logger_options = {
-        key: value for key, value in vars(options).iteritems()
+        key: value for key, value in vars(options.items())
         if key.startswith('log') or key == 'valgrind'}
 
     runner = MochitestDesktop(logger_options, quiet=options.quiet)
diff --git a/testing/mozbase/docs/_static/structured_example.py b/testing/mozbase/docs/_static/structured_example.py
index 2bbc038103..3a888fe338 100644
--- a/testing/mozbase/docs/_static/structured_example.py
+++ b/testing/mozbase/docs/_static/structured_example.py
@@ -12,7 +12,7 @@ class TestAssertion(Exception):
 
 def assert_equals(a, b):
     if a != b:
-        raise TestAssertion("%r not equal to %r" % (a, b))
+        raise TestAssertion("{!r} not equal to {!r}".format(a, b))
 
 
 def expected(status):
@@ -42,13 +42,13 @@ def test_expected_fail():
     assert_equals(2 + 2, 5)
 
 
-class TestRunner(object):
+class TestRunner:
 
     def __init__(self):
         self.logger = get_default_logger(component='TestRunner')
 
     def gather_tests(self):
-        for item in globals().itervalues():
+        for item in globals(.values()):
             if isinstance(item, types.FunctionType) and item.__name__.startswith("test_"):
                 yield item.__name__, item
 
diff --git a/testing/mozbase/docs/conf.py b/testing/mozbase/docs/conf.py
index 95d6de64ba..e2cf079996 100644
--- a/testing/mozbase/docs/conf.py
+++ b/testing/mozbase/docs/conf.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 #
 # MozBase documentation build configuration file, created by
 # sphinx-quickstart on Mon Oct 22 14:02:17 2012.
@@ -47,8 +46,8 @@ source_suffix = '.rst'
 master_doc = 'index'
 
 # General information about the project.
-project = u'MozBase'
-copyright = u'2012, Mozilla Automation and Tools team'
+project = 'MozBase'
+copyright = '2012, Mozilla Automation and Tools team'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -199,8 +198,8 @@ latex_elements = {
 # Grouping the document tree into LaTeX files. List of tuples
 # (source start file, target name, title, author, documentclass [howto/manual]).
 latex_documents = [
-    ('index', 'MozBase.tex', u'MozBase Documentation',
-     u'Mozilla Automation and Tools team', 'manual'),
+    ('index', 'MozBase.tex', 'MozBase Documentation',
+     'Mozilla Automation and Tools team', 'manual'),
 ]
 
 # The name of an image file (relative to this directory) to place at the top of
@@ -229,8 +228,8 @@ latex_documents = [
 # One entry per manual page. List of tuples
 # (source start file, name, description, authors, manual section).
 man_pages = [
-    ('index', 'mozbase', u'MozBase Documentation',
-     [u'Mozilla Automation and Tools team'], 1)
+    ('index', 'mozbase', 'MozBase Documentation',
+     ['Mozilla Automation and Tools team'], 1)
 ]
 
 # If true, show URL addresses after external links.
@@ -243,8 +242,8 @@ man_pages = [
 # (source start file, target name, title, author,
 #  dir menu entry, description, category)
 texinfo_documents = [
-    ('index', 'MozBase', u'MozBase Documentation',
-     u'Mozilla Automation and Tools team', 'MozBase', 'One line description of project.',
+    ('index', 'MozBase', 'MozBase Documentation',
+     'Mozilla Automation and Tools team', 'MozBase', 'One line description of project.',
      'Miscellaneous'),
 ]
 
diff --git a/testing/mozbase/manifestparser/manifestparser/cli.py b/testing/mozbase/manifestparser/manifestparser/cli.py
index 482575d292..d5d18580eb 100644
--- a/testing/mozbase/manifestparser/manifestparser/cli.py
+++ b/testing/mozbase/manifestparser/manifestparser/cli.py
@@ -7,6 +7,7 @@
 Mozilla universal manifest parser
 """
 
+from __future__ import print_function
 from optparse import OptionParser
 import os
 import sys
@@ -81,7 +82,7 @@ class Copy(CLICommand):
         # parse the arguments
         try:
             kwargs, tags, args = parse_args(args)
-        except ParserError, e:
+        except ParserError as e:
             self._parser.error(e.message)
 
         # make sure we have some manifests, otherwise it will
@@ -132,7 +133,7 @@ class CreateCLI(CLICommand):
             manifest = convert(args, pattern=options.pattern, ignore=options.ignore,
                                write=options.in_place)
         if manifest:
-            print manifest
+            print(manifest)
 
 
 class WriteCLI(CLICommand):
@@ -146,7 +147,7 @@ class WriteCLI(CLICommand):
         # parse the arguments
         try:
             kwargs, tags, args = parse_args(args)
-        except ParserError, e:
+        except ParserError as e:
             self._parser.error(e.message)
 
         # make sure we have some manifests, otherwise it will
@@ -175,9 +176,9 @@ class HelpCLI(CLICommand):
             commands[args[0]](self._parser).parser().print_help()
         else:
             self._parser.print_help()
-            print '\nCommands:'
+            print('\nCommands:')
             for command in sorted(commands):
-                print '  %s : %s' % (command, commands[command].__doc__.strip())
+                print(('  %s : %s' % (command, commands[command].__doc__.strip())))
 
 
 class UpdateCLI(CLICommand):
@@ -190,7 +191,7 @@ class UpdateCLI(CLICommand):
         # parse the arguments
         try:
             kwargs, tags, args = parse_args(args)
-        except ParserError, e:
+        except ParserError as e:
             self._parser.error(e.message)
 
         # make sure we have some manifests, otherwise it will
diff --git a/testing/mozbase/manifestparser/manifestparser/expression.py b/testing/mozbase/manifestparser/manifestparser/expression.py
index 6b705ead9c..6484e23c8a 100644
--- a/testing/mozbase/manifestparser/manifestparser/expression.py
+++ b/testing/mozbase/manifestparser/manifestparser/expression.py
@@ -195,7 +195,7 @@ class ExpressionParser(object):
         LITERAL ::= BOOL | INT | IDENT | STRING
         BOOL ::= 'true' | 'false'
         INT ::= [0-9]+
-        IDENT ::= [a-zA-Z_]\w*
+        IDENT ::= [a-zA-Z_]\\w*
         STRING ::= '"' [^\"] '"' | ''' [^\'] '''
 
     At its core, expressions consist of booleans, integers, identifiers and.
@@ -275,7 +275,7 @@ class ExpressionParser(object):
         """
         if not isinstance(self.token, expected):
             raise Exception("Unexpected token!")
-        self.token = self.iter.next()
+        self.token = next(self.iter)
 
     def expression(self, rbp=0):
         """
@@ -283,11 +283,11 @@ class ExpressionParser(object):
         right binding power greater than rbp is encountered.
         """
         t = self.token
-        self.token = self.iter.next()
+        self.token = next(self.iter)
         left = t.nud(self)
         while rbp < self.token.lbp:
             t = self.token
-            self.token = self.iter.next()
+            self.token = next(self.iter)
             left = t.led(self, left)
         return left
 
@@ -299,7 +299,7 @@ class ExpressionParser(object):
         """
         try:
             self.iter = self._tokenize()
-            self.token = self.iter.next()
+            self.token = next(self.iter)
             return self.expression()
         except:
             extype, ex, tb = sys.exc_info()
@@ -307,7 +307,7 @@ class ExpressionParser(object):
             raise ParseError("could not parse: "
                              "%s\nexception: %svariables: %s" % (self.text,
                                                                  formatted,
-                                                                 self.valuemapping)), None, tb
+                                                                 self.valuemapping)).with_traceback(tb)
 
     __call__ = parse
 
diff --git a/testing/mozbase/manifestparser/manifestparser/filters.py b/testing/mozbase/manifestparser/manifestparser/filters.py
index e832c0da65..0742b96eaf 100644
--- a/testing/mozbase/manifestparser/manifestparser/filters.py
+++ b/testing/mozbase/manifestparser/manifestparser/filters.py
@@ -8,7 +8,8 @@ dictionary of values, and returns a new iterable of test objects. It is
 possible to define custom filters if the built-in ones are not enough.
 """
 
-from collections import defaultdict, MutableSequence
+from collections import defaultdict
+from collections.abc import MutableSequence
 import itertools
 import os
 
@@ -79,7 +80,7 @@ def exists(tests, values):
 
 # built-in instance filters
 
-class InstanceFilter(object):
+class InstanceFilter:
     """
     Generally only one instance of a class filter should be applied at a time.
     Two instances of `InstanceFilter` are considered equal if they have the
@@ -92,7 +93,7 @@ class InstanceFilter(object):
     def __init__(self, *args, **kwargs):
         self.fmt_args = ', '.join(itertools.chain(
             [str(a) for a in args],
-            ['{}={}'.format(k, v) for k, v in kwargs.iteritems()]))
+            ['{}={}'.format(k, v) for k, v in kwargs.items()]))
 
     def __eq__(self, other):
         if self.unique:
@@ -249,10 +250,9 @@ class chunk_by_dir(InstanceFilter):
         # be yielded for reporting purposes. Put them all in chunk 1 for
         # simplicity.
         if self.this_chunk == 1:
-            disabled_dirs = [v for k, v in tests_by_dir.iteritems()
+            disabled_dirs = [v for k, v in tests_by_dir.items()
                              if k not in ordered_dirs]
-            for disabled_test in itertools.chain(*disabled_dirs):
-                yield disabled_test
+            yield from itertools.chain(*disabled_dirs)
 
 
 class chunk_by_runtime(InstanceFilter):
@@ -283,7 +283,7 @@ class chunk_by_runtime(InstanceFilter):
 
     def __call__(self, tests, values):
         tests = list(tests)
-        manifests = set(t['manifest'] for t in tests)
+        manifests = {t['manifest'] for t in tests}
 
         def total_runtime(tests):
             return sum(self.runtimes[t['relpath']] for t in tests
@@ -326,7 +326,7 @@ class tags(InstanceFilter):
 
     def __init__(self, tags):
         InstanceFilter.__init__(self, tags)
-        if isinstance(tags, basestring):
+        if isinstance(tags, str):
             tags = [tags]
         self.tags = tags
 
@@ -349,7 +349,7 @@ class pathprefix(InstanceFilter):
 
     def __init__(self, paths):
         InstanceFilter.__init__(self, paths)
-        if isinstance(paths, basestring):
+        if isinstance(paths, str):
             paths = [paths]
         self.paths = paths
 
diff --git a/testing/mozbase/manifestparser/manifestparser/ini.py b/testing/mozbase/manifestparser/manifestparser/ini.py
index 5117dd1ae8..254146f90e 100644
--- a/testing/mozbase/manifestparser/manifestparser/ini.py
+++ b/testing/mozbase/manifestparser/manifestparser/ini.py
@@ -27,11 +27,14 @@ def read_ini(fp, variables=None, default='DEFAULT', defaults_only=False,
     sections = []
     key = value = None
     section_names = set()
-    if isinstance(fp, basestring):
-        fp = file(fp)
+    if isinstance(fp, (str, bytes)):
+        fp = open(fp if isinstance(fp, str) else fp.decode('utf-8'))
 
     # read the lines
-    for (linenum, line) in enumerate(fp.read().splitlines(), start=1):
+    content = fp.read()
+    if isinstance(content, bytes):
+        content = content.decode('utf-8')
+    for (linenum, line) in enumerate(content.splitlines(), start=1):
 
         stripped = line.strip()
 
@@ -60,7 +63,7 @@ def read_ini(fp, variables=None, default='DEFAULT', defaults_only=False,
 
             if strict:
                 # make sure this section doesn't already exist
-                assert section not in section_names, "Section '%s' already found in '%s'" % (
+                assert section not in section_names, "Section '{}' already found in '{}'".format(
                     section, section_names)
 
             section_names.add(section)
@@ -90,7 +93,7 @@ def read_ini(fp, variables=None, default='DEFAULT', defaults_only=False,
         else:
             # continuation line ?
             if line[0].isspace() and key:
-                value = '%s%s%s' % (value, os.linesep, stripped)
+                value = '{}{}{}'.format(value, os.linesep, stripped)
                 current_section[key] = value
             else:
                 # something bad happened!
diff --git a/testing/mozbase/manifestparser/manifestparser/manifestparser.py b/testing/mozbase/manifestparser/manifestparser/manifestparser.py
index 23f14d3f87..216f79b8dc 100644
--- a/testing/mozbase/manifestparser/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestparser/manifestparser/manifestparser.py
@@ -2,7 +2,7 @@
 # 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 StringIO import StringIO
+from io import StringIO
 import json
 import fnmatch
 import os
@@ -21,7 +21,7 @@ from .filters import (
 __all__ = ['ManifestParser', 'TestManifest', 'convert']
 
 relpath = os.path.relpath
-string = (basestring,)
+string = (str,)
 
 
 # path normalization
@@ -42,7 +42,7 @@ def denormalize_path(path):
 
 # objects for parsing manifests
 
-class ManifestParser(object):
+class ManifestParser:
     """read .ini manifests"""
 
     def __init__(self, manifests=(), defaults=None, strict=True, rootdir=None,
@@ -110,7 +110,7 @@ class ManifestParser(object):
             if not self.path_exists(include_file):
                 message = "Included file '%s' does not exist" % include_file
                 if self.strict:
-                    raise IOError(message)
+                    raise OSError(message)
                 else:
                     sys.stderr.write("%s\n" % message)
                     return
@@ -178,7 +178,7 @@ class ManifestParser(object):
 
             # otherwise an item
             # apply ancestor defaults, while maintaining current file priority
-            data = dict(self._ancestor_defaults.items() + data.items())
+            data = dict(list(self._ancestor_defaults.items()) + list(data.items()))
 
             test = data
             test['name'] = section
@@ -249,7 +249,7 @@ class ManifestParser(object):
         missing = [filename for filename in filenames
                    if isinstance(filename, string) and not self.path_exists(filename)]
         if missing:
-            raise IOError('Missing files: %s' % ', '.join(missing))
+            raise OSError('Missing files: %s' % ', '.join(missing))
 
         # default variables
         _defaults = defaults.copy() or self._defaults.copy()
@@ -370,11 +370,11 @@ class ManifestParser(object):
         if missing:
             missing_paths = [test['path'] for test in missing]
             if self.strict:
-                raise IOError("Strict mode enabled, test paths must exist. "
+                raise OSError("Strict mode enabled, test paths must exist. "
                               "The following test(s) are missing: %s" %
                               json.dumps(missing_paths, indent=2))
-            print >> sys.stderr, "Warning: The following test(s) are missing: %s" % \
-                json.dumps(missing_paths, indent=2)
+            print("Warning: The following test(s) are missing: %s" %
+                json.dumps(missing_paths, indent=2), file=sys.stderr)
         return missing
 
     def verifyDirectory(self, directories, pattern=None, extensions=None):
@@ -384,8 +384,8 @@ class ManifestParser(object):
         (missing_from_filesystem, missing_from_manifest)
         """
 
-        files = set([])
-        if isinstance(directories, basestring):
+        files = set()
+        if isinstance(directories, str):
             directories = [directories]
 
         # get files in directories
@@ -437,7 +437,7 @@ class ManifestParser(object):
         local_kwargs = local_kwargs or {}
 
         # create the query
-        tags = set([])
+        tags = set()
         tags.update(global_tags)
         tags.update(local_tags)
         kwargs = {}
@@ -449,12 +449,12 @@ class ManifestParser(object):
 
         # print the .ini manifest
         if global_tags or global_kwargs:
-            print >> fp, '[DEFAULT]'
+            print('[DEFAULT]', file=fp)
             for tag in global_tags:
-                print >> fp, '%s =' % tag
+                print('%s =' % tag, file=fp)
             for key, value in global_kwargs.items():
-                print >> fp, '%s = %s' % (key, value)
-            print >> fp
+                print('{} = {}'.format(key, value, file=fp))
+            print(self.rootdir, file=fp)
 
         for test in tests:
             test = test.copy()  # don't overwrite
@@ -463,9 +463,9 @@ class ManifestParser(object):
             if not os.path.isabs(path):
                 path = test['path']
                 if self.rootdir:
-                    path = relpath(test['path'], self.rootdir)
+                    path = relpath(test['path'])
                 path = denormalize_path(path)
-            print >> fp, '[%s]' % path
+            print('[%s]' % path, file=fp)
 
             # reserved keywords:
             reserved = ['path', 'name', 'here', 'manifest', 'relpath', 'ancestor-manifest']
@@ -476,8 +476,8 @@ class ManifestParser(object):
                     continue
                 if key in global_tags and not test[key]:
                     continue
-                print >> fp, '%s = %s' % (key, test[key])
-            print >> fp
+                print('{} = {}'.format(key, test[key], file=fp))
+            print(directory, rootdir=None, *tags, **kwargs, file=fp)
 
         if close:
             # close the created file
@@ -489,7 +489,7 @@ class ManifestParser(object):
         value = fp.getvalue()
         return value
 
-    def copy(self, directory, rootdir=None, *tags, **kwargs):
+    def copy(self):
         """
         copy the manifests and associated tests
         - directory : directory to copy to
@@ -564,8 +564,8 @@ class ManifestParser(object):
                 if not os.path.exists(source):
                     message = "Missing test: '%s' does not exist!"
                     if self.strict:
-                        raise IOError(message)
-                    print >> sys.stderr, message + " Skipping."
+                        raise OSError(message)
+                    print(message + " Skipping.", file=sys.stderr)
                     continue
                 destination = os.path.join(rootdir, _relpath)
                 shutil.copy(source, destination)
@@ -578,7 +578,7 @@ class ManifestParser(object):
         internal function to import directories
         """
 
-        if isinstance(pattern, basestring):
+        if isinstance(pattern, str):
             patterns = [pattern]
         else:
             patterns = pattern
@@ -654,7 +654,7 @@ class ManifestParser(object):
         manifest_dict = {}
 
         if os.path.basename(filename) != filename:
-            raise IOError("filename should not include directory name")
+            raise OSError("filename should not include directory name")
 
         # no need to hit directories more than once
         _directories = directories
@@ -670,9 +670,9 @@ class ManifestParser(object):
             if (dirnames or filenames) and not (os.path.exists(manifest_path) and overwrite):
                 with file(manifest_path, 'w') as manifest:
                     for dirname in dirnames:
-                        print >> manifest, '[include:%s]' % os.path.join(dirname, filename)
+                        print('[include:%s]' % os.path.join(dirname, filename, file=manifest))
                     for _filename in filenames:
-                        print >> manifest, '[%s]' % _filename
+                        print('[%s]' % _filename, file=manifest)
 
                 # add to list of manifests
                 manifest_dict.setdefault(directory, manifest_path)
@@ -722,8 +722,8 @@ class ManifestParser(object):
                              for filename in filenames]
 
             # write to manifest
-            print >> write, '\n'.join(['[%s]' % denormalize_path(filename)
-                                       for filename in filenames])
+            print('\n'.join(['[%s]' % denormalize_path(filename)
+                                       for filename in filenames]), file=write)
 
         cls._walk_directories(directories, callback, pattern=pattern, ignore=ignore)
 
diff --git a/testing/mozbase/manifestparser/tests/test_chunking.py b/testing/mozbase/manifestparser/tests/test_chunking.py
index 719bbca80c..56022dd7de 100644
--- a/testing/mozbase/manifestparser/tests/test_chunking.py
+++ b/testing/mozbase/manifestparser/tests/test_chunking.py
@@ -63,7 +63,7 @@ class ChunkBySlice(TestCase):
         self.run_all_combos(num_tests=10, disabled=[1, 2])
 
         num_tests = 67
-        disabled = list(i for i in xrange(num_tests) if i % 4 == 0)
+        disabled = list(i for i in range(num_tests) if i % 4 == 0)
         self.run_all_combos(num_tests=num_tests, disabled=disabled)
 
     def test_two_times_more_chunks_than_tests(self):
@@ -85,7 +85,7 @@ class ChunkByDir(TestCase):
                         { <dir>: <num tests> }
         """
         i = 0
-        for d, num in dirs.iteritems():
+        for d, num in dirs.items():
             for j in range(num):
                 i += 1
                 name = 'test%i' % i
@@ -113,7 +113,7 @@ class ChunkByDir(TestCase):
                     f = chunk_by_dir(this, total, depth)
                     res.append(list(f(tests, {})))
 
-                lengths = map(num_groups, res)
+                lengths = list(map(num_groups, res))
                 # the chunk with the most dirs should have at most one more
                 # dir than the chunk with the least dirs
                 self.assertLessEqual(max(lengths) - min(lengths), 1)
@@ -176,7 +176,7 @@ class ChunkByRuntime(TestCase):
                      { <dir>: <num tests> }
         """
         i = 0
-        for d, num in dirs.iteritems():
+        for d, num in dirs.items():
             for j in range(num):
                 i += 1
                 name = 'test%i' % i
@@ -192,7 +192,7 @@ class ChunkByRuntime(TestCase):
         return runtimes
 
     def chunk_by_round_robin(self, tests, runtimes):
-        manifests = set(t['manifest'] for t in tests)
+        manifests = {t['manifest'] for t in tests}
         tests_by_manifest = []
         for manifest in manifests:
             mtests = [t for t in tests if t['manifest'] == manifest]
diff --git a/testing/mozbase/manifestparser/tests/test_convert_directory.py b/testing/mozbase/manifestparser/tests/test_convert_directory.py
index 12776e4e4f..669ca84ada 100755
--- a/testing/mozbase/manifestparser/tests/test_convert_directory.py
+++ b/testing/mozbase/manifestparser/tests/test_convert_directory.py
@@ -39,10 +39,10 @@ class TestDirectoryConversion(unittest.TestCase):
         if directory is None:
             directory = create_realpath_tempdir()
         for i in files:
-            file(os.path.join(directory, i), 'w').write(i)
+            open(os.path.join(directory, i), 'w').write(i)
         subdir = os.path.join(directory, 'subdir')
         os.mkdir(subdir)
-        file(os.path.join(subdir, 'subfile'), 'w').write('baz')
+        open(os.path.join(subdir, 'subfile'), 'w').write('baz')
         return directory
 
     def test_directory_to_manifest(self):
@@ -141,13 +141,13 @@ class TestDirectoryConversion(unittest.TestCase):
         # boilerplate
         tempdir = create_realpath_tempdir()
         for i in range(10):
-            file(os.path.join(tempdir, str(i)), 'w').write(str(i))
+            open(os.path.join(tempdir, str(i)), 'w').write(str(i))
 
         # otherwise empty directory with a manifest file
         newtempdir = create_realpath_tempdir()
         manifest_file = os.path.join(newtempdir, 'manifest.ini')
         manifest_contents = str(convert([tempdir], relative_to=tempdir))
-        with file(manifest_file, 'w') as f:
+        with open(manifest_file, 'w') as f:
             f.write(manifest_contents)
 
         # get the manifest
@@ -165,11 +165,11 @@ class TestDirectoryConversion(unittest.TestCase):
                          ['1', 'manifest.ini'])
 
         # Update that one file and copy all the "tests":
-        file(os.path.join(tempdir, '1'), 'w').write('secret door')
+        open(os.path.join(tempdir, '1'), 'w').write('secret door')
         manifest.update(tempdir)
         self.assertEqual(sorted(os.listdir(newtempdir)),
                          ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'manifest.ini'])
-        self.assertEqual(file(os.path.join(newtempdir, '1')).read().strip(),
+        self.assertEqual(open(os.path.join(newtempdir, '1')).read().strip(),
                          'secret door')
 
         # clean up:
diff --git a/testing/mozbase/manifestparser/tests/test_convert_symlinks.py b/testing/mozbase/manifestparser/tests/test_convert_symlinks.py
index 9a0640b4bd..dac027cdff 100755
--- a/testing/mozbase/manifestparser/tests/test_convert_symlinks.py
+++ b/testing/mozbase/manifestparser/tests/test_convert_symlinks.py
@@ -24,10 +24,10 @@ class TestSymlinkConversion(unittest.TestCase):
         if directory is None:
             directory = tempfile.mkdtemp()
         for i in files:
-            file(os.path.join(directory, i), 'w').write(i)
+            open(os.path.join(directory, i), 'w').write(i)
         subdir = os.path.join(directory, 'subdir')
         os.mkdir(subdir)
-        file(os.path.join(subdir, 'subfile'), 'w').write('baz')
+        open(os.path.join(subdir, 'subfile'), 'w').write('baz')
         return directory
 
     def test_relpath(self):
diff --git a/testing/mozbase/manifestparser/tests/test_filters.py b/testing/mozbase/manifestparser/tests/test_filters.py
index 5b0772492e..5334ae2b55 100644
--- a/testing/mozbase/manifestparser/tests/test_filters.py
+++ b/testing/mozbase/manifestparser/tests/test_filters.py
@@ -28,19 +28,19 @@ class FilterList(unittest.TestCase):
         fl = filterlist()
 
         fl.extend([foo, bar])
-        self.assertEquals(len(fl), 2)
+        self.assertEqual(len(fl), 2)
         self.assertTrue(foo in fl)
 
         fl.append(baz)
-        self.assertEquals(fl[2], baz)
+        self.assertEqual(fl[2], baz)
 
         fl.remove(baz)
         self.assertFalse(baz in fl)
 
         item = fl.pop()
-        self.assertEquals(item, bar)
+        self.assertEqual(item, bar)
 
-        self.assertEquals(fl.index(foo), 0)
+        self.assertEqual(fl.index(foo), 0)
 
         del fl[0]
         self.assertFalse(foo in fl)
@@ -57,8 +57,8 @@ class FilterList(unittest.TestCase):
         bar = lambda x, y: x
         sub = subsuite('foo')
         fl = filterlist([foo, bar, sub])
-        self.assertEquals(len(fl), 3)
-        self.assertEquals(fl[0], foo)
+        self.assertEqual(len(fl), 3)
+        self.assertEqual(fl[0], foo)
 
         with self.assertRaises(ValueError):
             fl.append(foo)
@@ -75,7 +75,7 @@ class FilterList(unittest.TestCase):
             fl.append(tag1)
 
         fl.append(tag2)
-        self.assertEquals(len(fl), 2)
+        self.assertEqual(len(fl), 2)
 
     def test_filters_run_in_order(self):
         a = lambda x, y: x
@@ -89,7 +89,7 @@ class FilterList(unittest.TestCase):
         fl.append(c)
         fl.extend([d, e])
         fl += [f]
-        self.assertEquals([i for i in fl], [a, b, c, d, e, f])
+        self.assertEqual([i for i in fl], [a, b, c, d, e, f])
 
 
 class BuiltinFilters(unittest.TestCase):
@@ -109,7 +109,7 @@ class BuiltinFilters(unittest.TestCase):
     def test_skip_if(self):
         tests = deepcopy(self.tests)
         tests = list(skip_if(tests, {}))
-        self.assertEquals(len(tests), len(self.tests))
+        self.assertEqual(len(tests), len(self.tests))
 
         tests = deepcopy(self.tests)
         tests = list(skip_if(tests, {'foo': 'bar'}))
@@ -122,7 +122,7 @@ class BuiltinFilters(unittest.TestCase):
 
         tests = deepcopy(self.tests)
         tests = list(run_if(tests, {'foo': 'bar'}))
-        self.assertEquals(len(tests), len(self.tests))
+        self.assertEqual(len(tests), len(self.tests))
 
     def test_fail_if(self):
         tests = deepcopy(self.tests)
@@ -131,7 +131,7 @@ class BuiltinFilters(unittest.TestCase):
 
         tests = deepcopy(self.tests)
         tests = list(fail_if(tests, {'foo': 'bar'}))
-        self.assertEquals(tests[3]['expected'], 'fail')
+        self.assertEqual(tests[3]['expected'], 'fail')
 
     def test_enabled(self):
         tests = deepcopy(self.tests)
@@ -145,11 +145,11 @@ class BuiltinFilters(unittest.TestCase):
         tests = deepcopy(self.tests)
         tests = list(sub1(tests, {}))
         self.assertNotIn(self.tests[5], tests)
-        self.assertEquals(len(tests), len(self.tests) - 1)
+        self.assertEqual(len(tests), len(self.tests) - 1)
 
         tests = deepcopy(self.tests)
         tests = list(sub2(tests, {}))
-        self.assertEquals(len(tests), 1)
+        self.assertEqual(len(tests), 1)
         self.assertIn(self.tests[5], tests)
 
     def test_subsuite_condition(self):
@@ -164,9 +164,9 @@ class BuiltinFilters(unittest.TestCase):
 
         tests = deepcopy(self.tests)
         tests = list(sub2(tests, {'foo': 'bar'}))
-        self.assertEquals(len(tests), 2)
-        self.assertEquals(tests[0]['name'], 'test5')
-        self.assertEquals(tests[1]['name'], 'test6')
+        self.assertEqual(len(tests), 2)
+        self.assertEqual(tests[0]['name'], 'test5')
+        self.assertEqual(tests[1]['name'], 'test6')
 
     def test_tags(self):
         ftags1 = tags([])
@@ -174,9 +174,9 @@ class BuiltinFilters(unittest.TestCase):
 
         tests = deepcopy(self.tests)
         tests = list(ftags1(tests, {}))
-        self.assertEquals(len(tests), 0)
+        self.assertEqual(len(tests), 0)
 
         tests = deepcopy(self.tests)
         tests = list(ftags2(tests, {}))
-        self.assertEquals(len(tests), 1)
+        self.assertEqual(len(tests), 1)
         self.assertIn(self.tests[7], tests)
diff --git a/testing/mozbase/manifestparser/tests/test_manifestparser.py b/testing/mozbase/manifestparser/tests/test_manifestparser.py
index ca80911fb9..0d3eaaf31d 100755
--- a/testing/mozbase/manifestparser/tests/test_manifestparser.py
+++ b/testing/mozbase/manifestparser/tests/test_manifestparser.py
@@ -29,11 +29,11 @@ class TestManifestParser(unittest.TestCase):
         mozmill_example = os.path.join(here, 'mozmill-example.ini')
         parser.read(mozmill_example)
         tests = parser.tests
-        self.assertEqual(len(tests), len(file(mozmill_example).read().strip().splitlines()))
+        self.assertEqual(len(tests), len(open(mozmill_example).read().strip().splitlines()))
 
         # Ensure that capitalization and order aren't an issue:
         lines = ['[%s]' % test['name'] for test in tests]
-        self.assertEqual(lines, file(mozmill_example).read().strip().splitlines())
+        self.assertEqual(lines, open(mozmill_example).read().strip().splitlines())
 
         # Show how you select subsets of tests:
         mozmill_restart_example = os.path.join(here, 'mozmill-restart-example.ini')
@@ -290,14 +290,14 @@ yellow = submarine"""  # noqa
         manifest_path = os.path.join(directory, 'verifyDirectory_incomplete.ini')
         manifest = ManifestParser(manifests=(manifest_path,))
         missing = manifest.verifyDirectory(directory, extensions=('.js',))
-        self.assertEqual(missing, (set(), set([test_1])))
+        self.assertEqual(missing, (set(), {test_1}))
 
         # filesystem is missing test_notappearinginthisfilm.js
         missing_test = os.path.join(directory, 'test_notappearinginthisfilm.js')
         manifest_path = os.path.join(directory, 'verifyDirectory_toocomplete.ini')
         manifest = ManifestParser(manifests=(manifest_path,))
         missing = manifest.verifyDirectory(directory, extensions=('.js',))
-        self.assertEqual(missing, (set([missing_test]), set()))
+        self.assertEqual(missing, ({missing_test}, set()))
 
     def test_just_defaults(self):
         """Ensure a manifest with just a DEFAULT section exposes that data."""
@@ -307,7 +307,7 @@ yellow = submarine"""  # noqa
         parser.read(manifest)
         self.assertEqual(len(parser.tests), 0)
         self.assertTrue(manifest in parser.manifest_defaults)
-        self.assertEquals(parser.manifest_defaults[manifest]['foo'], 'bar')
+        self.assertEqual(parser.manifest_defaults[manifest]['foo'], 'bar')
 
     def test_manifest_list(self):
         """
diff --git a/testing/mozbase/manifestparser/tests/test_read_ini.py b/testing/mozbase/manifestparser/tests/test_read_ini.py
index df4a8973b0..960c001535 100755
--- a/testing/mozbase/manifestparser/tests/test_read_ini.py
+++ b/testing/mozbase/manifestparser/tests/test_read_ini.py
@@ -12,7 +12,7 @@ http://docs.python.org/2/library/configparser.html
 
 import unittest
 from manifestparser import read_ini
-from ConfigParser import ConfigParser
+from configparser import ConfigParser
 from StringIO import StringIO
 
 
diff --git a/testing/mozbase/manifestparser/tests/test_testmanifest.py b/testing/mozbase/manifestparser/tests/test_testmanifest.py
index 5f79dd48a6..8ded6b2fc1 100644
--- a/testing/mozbase/manifestparser/tests/test_testmanifest.py
+++ b/testing/mozbase/manifestparser/tests/test_testmanifest.py
@@ -71,24 +71,24 @@ class TestTestManifest(unittest.TestCase):
 
         # 6 tests total
         tests = manifest.active_tests(exists=False, **info)
-        self.assertEquals(len(tests), 6)
+        self.assertEqual(len(tests), 6)
 
         # only 3 tests for subsuite bar when foo==bar
         tests = manifest.active_tests(exists=False,
                                       filters=[subsuite('bar')],
                                       **info)
-        self.assertEquals(len(tests), 3)
+        self.assertEqual(len(tests), 3)
 
         # only 1 test for subsuite baz, regardless of conditions
         other = {'something': 'else'}
         tests = manifest.active_tests(exists=False,
                                       filters=[subsuite('baz')],
                                       **info)
-        self.assertEquals(len(tests), 1)
+        self.assertEqual(len(tests), 1)
         tests = manifest.active_tests(exists=False,
                                       filters=[subsuite('baz')],
                                       **other)
-        self.assertEquals(len(tests), 1)
+        self.assertEqual(len(tests), 1)
 
         # 4 tests match when the condition doesn't match (all tests except
         # the unconditional subsuite)
@@ -96,7 +96,7 @@ class TestTestManifest(unittest.TestCase):
         tests = manifest.active_tests(exists=False,
                                       filters=[subsuite()],
                                       **info)
-        self.assertEquals(len(tests), 5)
+        self.assertEqual(len(tests), 5)
 
         # test for illegal subsuite value
         manifest.tests[0]['subsuite'] = 'subsuite=bar,foo=="bar",type="nothing"'
diff --git a/testing/mozbase/mozcrash/mozcrash/__init__.py b/testing/mozbase/mozcrash/mozcrash/__init__.py
index ec95442cf2..29a487571b 100644
--- a/testing/mozbase/mozcrash/mozcrash/__init__.py
+++ b/testing/mozbase/mozcrash/mozcrash/__init__.py
@@ -7,4 +7,4 @@ mozcrash is a library for getting a stack trace out of processes that have crash
 and left behind a minidump file using the Google Breakpad library.
 """
 
-from mozcrash import *
+from .mozcrash import *
diff --git a/testing/mozbase/mozcrash/mozcrash/mozcrash.py b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
index c39e68f3a6..1da425b9d8 100644
--- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -105,10 +105,10 @@ def check_for_crashes(dump_directory,
                 stackwalk_output.append("minidump_stackwalk exited with return code %d" %
                                         info.stackwalk_retcode)
             signature = info.signature if info.signature else "unknown top frame"
-            print "PROCESS-CRASH | %s | application crashed [%s]" % (test_name,
+            print("PROCESS-CRASH | %s | application crashed [%s]" % (test_name,)
                                                                      signature)
-            print '\n'.join(stackwalk_output)
-            print '\n'.join(info.stackwalk_errors)
+            print('\n'.join(stackwalk_output))
+            print('\n'.join(info.stackwalk_errors))
 
     return crash_count
 
@@ -371,11 +371,11 @@ def check_for_java_exception(logcat, test_name=None, quiet=False):
                 if m and m.group(1):
                     exception_location = m.group(1)
                 if not quiet:
-                    print "PROCESS-CRASH | %s | java-exception %s %s" % (test_name,
+                    print("PROCESS-CRASH | %s | java-exception %s %s" % (test_name,)
                                                                          exception_type,
                                                                          exception_location)
             else:
-                print "Automation Error: java exception in logcat at line " \
+                print("Automation Error: java exception in logcat at line " \)
                     "%d of %d: %s" % (i, len(logcat), line)
             break
 
diff --git a/testing/mozbase/mozcrash/tests/test.py b/testing/mozbase/mozcrash/tests/test.py
index 8f6b14f50b..1d71684dbb 100644
--- a/testing/mozbase/mozcrash/tests/test.py
+++ b/testing/mozbase/mozcrash/tests/test.py
@@ -9,7 +9,7 @@ import unittest
 import subprocess
 import tempfile
 import shutil
-import urlparse
+import six.moves.urllib.parse
 import zipfile
 import StringIO
 import mozcrash
@@ -25,17 +25,17 @@ def popen_factory(stdouts):
     Generate a class that can mock subprocess.Popen. |stdouts| is an iterable that
     should return an iterable for the stdout of each process in turn.
     """
-    class mock_popen(object):
+    class mock_popen:
 
         def __init__(self, args, *args_rest, **kwargs):
-            self.stdout = stdouts.next()
+            self.stdout = next(stdouts)
             self.returncode = 0
 
         def wait(self):
             return 0
 
         def communicate(self):
-            return (self.stdout.next(), "")
+            return (next(self.stdout), "")
 
     return mock_popen
 
@@ -77,7 +77,7 @@ class TestCrash(unittest.TestCase):
         """
         open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
         self.stdouts.append(["this is some output"])
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 stackwalk_binary=self.stackwalk,
                                                 quiet=True))
@@ -89,7 +89,7 @@ class TestCrash(unittest.TestCase):
         open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
         self.stdouts.append(["this is some output"])
         os.environ['MINIDUMP_STACKWALK'] = self.stackwalk
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 quiet=True))
         del os.environ['MINIDUMP_STACKWALK']
@@ -103,13 +103,13 @@ class TestCrash(unittest.TestCase):
         save_path = os.path.join(self.tempdir, "saved")
         os.mkdir(save_path)
         self.stdouts.append(["this is some output"])
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 stackwalk_binary=self.stackwalk,
                                                 dump_save_path=save_path,
                                                 quiet=True))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.dmp")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.extra")))
 
     def test_save_path_not_present(self):
         """
@@ -119,13 +119,13 @@ class TestCrash(unittest.TestCase):
         open(os.path.join(self.tempdir, "test.extra"), "w").write("bar")
         save_path = os.path.join(self.tempdir, "saved")
         self.stdouts.append(["this is some output"])
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 stackwalk_binary=self.stackwalk,
                                                 dump_save_path=save_path,
                                                 quiet=True))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.dmp")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.extra")))
 
     def test_save_path_isfile(self):
         """
@@ -137,13 +137,13 @@ class TestCrash(unittest.TestCase):
         save_path = os.path.join(self.tempdir, "saved")
         open(save_path, "w").write("junk")
         self.stdouts.append(["this is some output"])
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 stackwalk_binary=self.stackwalk,
                                                 dump_save_path=save_path,
                                                 quiet=True))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.dmp")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.extra")))
 
     def test_save_path_envvar(self):
         """
@@ -155,18 +155,18 @@ class TestCrash(unittest.TestCase):
         os.mkdir(save_path)
         self.stdouts.append(["this is some output"])
         os.environ['MINIDUMP_SAVE_PATH'] = save_path
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path='symbols_path',
                                                 stackwalk_binary=self.stackwalk,
                                                 quiet=True))
         del os.environ['MINIDUMP_SAVE_PATH']
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.dmp")))
-        self.assert_(os.path.isfile(os.path.join(save_path, "test.extra")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.dmp")))
+        self.assertTrue(os.path.isfile(os.path.join(save_path, "test.extra")))
 
     def test_symbol_path_not_present(self):
         open(os.path.join(self.tempdir, "test.dmp"), "w").write("foo")
         self.stdouts.append(["this is some output"])
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbols_path=None,
                                                 stackwalk_binary=self.stackwalk,
                                                 quiet=True))
@@ -193,9 +193,9 @@ class TestCrash(unittest.TestCase):
                                                 'path': '/symbols',
                                                 'function': get_symbols}])
         httpd.start()
-        symbol_url = urlparse.urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
+        symbol_url = six.moves.urllib.parse.urlunsplit(('http', '%s:%d' % httpd.httpd.server_address,
                                           '/symbols', '', ''))
-        self.assert_(mozcrash.check_for_crashes(self.tempdir,
+        self.assertTrue(mozcrash.check_for_crashes(self.tempdir,
                                                 symbol_url,
                                                 stackwalk_binary=self.stackwalk,
                                                 quiet=True))
@@ -217,7 +217,7 @@ class TestJavaException(unittest.TestCase):
         """
         Test for an exception which should be caught
         """
-        self.assert_(mozcrash.check_for_java_exception(self.test_log, quiet=True))
+        self.assertTrue(mozcrash.check_for_java_exception(self.test_log, quiet=True))
 
     def test_truncated_exception(self):
         """
@@ -226,7 +226,7 @@ class TestJavaException(unittest.TestCase):
         """
         truncated_log = list(self.test_log)
         truncated_log[0], truncated_log[1] = truncated_log[1], truncated_log[0]
-        self.assert_(mozcrash.check_for_java_exception(truncated_log, quiet=True))
+        self.assertTrue(mozcrash.check_for_java_exception(truncated_log, quiet=True))
 
     def test_unchecked_exception(self):
         """
@@ -235,7 +235,7 @@ class TestJavaException(unittest.TestCase):
         passable_log = list(self.test_log)
         passable_log[0] = "01-30 20:15:41.937 E/GeckoAppShell( 1703):" \
                           " >>> NOT-SO-BAD EXCEPTION FROM THREAD 9 (\"GeckoBackgroundThread\")"
-        self.assert_(not mozcrash.check_for_java_exception(passable_log, quiet=True))
+        self.assertTrue(not mozcrash.check_for_java_exception(passable_log, quiet=True))
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/testing/mozbase/mozdebug/mozdebug/__init__.py b/testing/mozbase/mozdebug/mozdebug/__init__.py
index 3450d755c7..63e9bd6140 100644
--- a/testing/mozbase/mozdebug/mozdebug/__init__.py
+++ b/testing/mozbase/mozdebug/mozdebug/__init__.py
@@ -28,4 +28,4 @@ debugger-specific arguments:
 
 """
 
-from mozdebug import *
+from .mozdebug import *
diff --git a/testing/mozbase/mozdebug/mozdebug/mozdebug.py b/testing/mozbase/mozdebug/mozdebug/mozdebug.py
index 6dd9e9fddd..8c6e9fbcc0 100755
--- a/testing/mozbase/mozdebug/mozdebug/mozdebug.py
+++ b/testing/mozbase/mozdebug/mozdebug/mozdebug.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import os
 import mozinfo
 from collections import namedtuple
@@ -163,7 +164,7 @@ def get_debugger_info(debugger, debuggerArgs=None, debuggerInteractive=False):
                 debuggerPath = debugger
 
     if not debuggerPath:
-        print 'Error: Could not find debugger %s.' % debugger
+        print(('Error: Could not find debugger %s.' % debugger))
         return None
 
     debuggerName = os.path.basename(debuggerPath).lower()
diff --git a/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py b/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
index 2b223bb044..f871a0c3ed 100644
--- a/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
+++ b/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
@@ -5,6 +5,7 @@
  Running this test case requires various reboots which makes it a
  very slow test case to run.
 """
+from __future__ import print_function
 import unittest
 import sys
 
@@ -36,13 +37,13 @@ class TestFileOperations(unittest.TestCase):
 if __name__ == "__main__":
     dm = DeviceManagerADB()
     if not dm.devices():
-        print "There are no connected adb devices"
+        print("There are no connected adb devices")
         sys.exit(1)
     else:
         if not (int(dm._runCmd(["shell", "getprop", "ro.secure"]).output[0]) and
                 int(dm._runCmd(["shell", "getprop", "ro.debuggable"]).output[0])):
-            print "This test case is meant for devices with devices that start " \
-                "adbd as non-root and allows for adbd to be restarted as root."
+            print("This test case is meant for devices with devices that start " \
+                "adbd as non-root and allows for adbd to be restarted as root.")
             sys.exit(1)
 
     unittest.main()
diff --git a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
index 495e449a4a..c85ccee7f9 100644
--- a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
@@ -34,6 +34,7 @@
  - uninstallAppAndReboot()
 """
 
+from __future__ import print_function
 import os
 import re
 import socket
@@ -207,13 +208,13 @@ class TestOther(DeviceManagerADBTestCase):
 if __name__ == '__main__':
     dm = DeviceManagerADB()
     if not dm.devices():
-        print "There are no connected adb devices"
+        print("There are no connected adb devices")
         sys.exit(1)
 
     if find_mount_permissions(dm, "/system") == "rw":
-        print "We've found out that /system is mounted as 'rw'. This is because the command " \
+        print("We've found out that /system is mounted as 'rw'. This is because the command " \
             "'adb remount' has been run before running this test case. Please reboot the device " \
-            "and try again."
+            "and try again.")
         sys.exit(1)
 
     unittest.main()
diff --git a/testing/mozbase/mozdevice/mozdevice/Zeroconf.py b/testing/mozbase/mozdevice/mozdevice/Zeroconf.py
index 54a5d53598..a709f5b290 100755
--- a/testing/mozbase/mozdevice/mozdevice/Zeroconf.py
+++ b/testing/mozbase/mozdevice/mozdevice/Zeroconf.py
@@ -74,6 +74,8 @@
                  ensure names end in '.local.'
                  timeout on receiving socket for clean shutdown"""
 
+from __future__ import print_function
+from functools import reduce
 __author__ = "Paul Scott-Murphy"
 __email__ = "paul at scott dash murphy dot com"
 __version__ = "0.12"
@@ -819,7 +821,7 @@ class DNSCache(object):
         """Returns a list of all entries"""
         def add(x, y): return x+y
         try:
-            return reduce(add, self.cache.values())
+            return reduce(add, list(self.cache.values()))
         except:
             return []
 
@@ -870,7 +872,7 @@ class Engine(threading.Thread):
     def getReaders(self):
         result = []
         self.condition.acquire()
-        result = self.readers.keys()
+        result = list(self.readers.keys())
         self.condition.release()
         return result
     
@@ -1062,7 +1064,7 @@ class ServiceInfo(object):
             for key in properties:
                 value = properties[key]
                 if value is None:
-                    suffix = ''.encode('utf-8')
+                    suffix = b''
                 elif isinstance(value, str):
                     suffix = value.encode('utf-8')
                 elif isinstance(value, int):
@@ -1071,7 +1073,7 @@ class ServiceInfo(object):
                     else:
                         suffix = 'false'
                 else:
-                    suffix = ''.encode('utf-8')
+                    suffix = b''
                 list.append('='.join((key, suffix)))
             for item in list:
                 result = ''.join((result, struct.pack('!c', chr(len(item))), item))
@@ -1540,21 +1542,21 @@ class Zeroconf(object):
 # query (for Zoe), and service unregistration.
 
 if __name__ == '__main__':    
-    print "Multicast DNS Service Discovery for Python, version", __version__
+    print(("Multicast DNS Service Discovery for Python, version", __version__))
     r = Zeroconf()
-    print "1. Testing registration of a service..."
+    print("1. Testing registration of a service...")
     desc = {'version':'0.10','a':'test value', 'b':'another value'}
     info = ServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.", socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
-    print "   Registering service..."
+    print("   Registering service...")
     r.registerService(info)
-    print "   Registration done."
-    print "2. Testing query of service information..."
-    print "   Getting ZOE service:", str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local."))
-    print "   Query done."
-    print "3. Testing query of own service..."
-    print "   Getting self:", str(r.getServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local."))
-    print "   Query done."
-    print "4. Testing unregister of service information..."
+    print("   Registration done.")
+    print("2. Testing query of service information...")
+    print(("   Getting ZOE service:", str(r.getServiceInfo("_http._tcp.local.", "ZOE._http._tcp.local."))))
+    print("   Query done.")
+    print("3. Testing query of own service...")
+    print(("   Getting self:", str(r.getServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local."))))
+    print("   Query done.")
+    print("4. Testing unregister of service information...")
     r.unregisterService(info)
-    print "   Unregister done."
+    print("   Unregister done.")
     r.close()
diff --git a/testing/mozbase/mozdevice/mozdevice/__init__.py b/testing/mozbase/mozdevice/mozdevice/__init__.py
index 2493f75db2..5e5b3d9881 100644
--- a/testing/mozbase/mozdevice/mozdevice/__init__.py
+++ b/testing/mozbase/mozdevice/mozdevice/__init__.py
@@ -2,13 +2,13 @@
 # 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 adb import ADBError, ADBRootError, ADBTimeoutError, ADBProcess, ADBCommand, ADBHost, ADBDevice
-from adb_android import ADBAndroid
-from adb_b2g import ADBB2G
-from devicemanager import DeviceManager, DMError, ZeroconfListener
-from devicemanagerADB import DeviceManagerADB
-from devicemanagerSUT import DeviceManagerSUT
-from droid import DroidADB, DroidSUT, DroidConnectByHWID
+from .adb import ADBError, ADBRootError, ADBTimeoutError, ADBProcess, ADBCommand, ADBHost, ADBDevice
+from .adb_android import ADBAndroid
+from .adb_b2g import ADBB2G
+from .devicemanager import DeviceManager, DMError, ZeroconfListener
+from .devicemanagerADB import DeviceManagerADB
+from .devicemanagerSUT import DeviceManagerSUT
+from .droid import DroidADB, DroidSUT, DroidConnectByHWID
 
 __all__ = ['ADBError', 'ADBRootError', 'ADBTimeoutError', 'ADBProcess', 'ADBCommand', 'ADBHost',
            'ADBDevice', 'ADBAndroid', 'ADBB2G', 'DeviceManager', 'DMError', 'ZeroconfListener',
diff --git a/testing/mozbase/mozdevice/mozdevice/adb.py b/testing/mozbase/mozdevice/mozdevice/adb.py
index 5958937d9a..5b9ea58ae0 100644
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -13,9 +13,10 @@ import traceback
 
 from abc import ABCMeta, abstractmethod
 from distutils import dir_util
+import six
 
 
-class ADBProcess(object):
+class ADBProcess:
     """ADBProcess encapsulates the data related to executing the adb process."""
 
     def __init__(self, args):
@@ -43,7 +44,7 @@ class ADBProcess(object):
         return content
 
     def __str__(self):
-        return ('args: %s, exitcode: %s, stdout: %s' % (
+        return ('args: {}, exitcode: {}, stdout: {}'.format(
             ' '.join(self.args), self.exitcode, self.stdout))
 
 # ADBError, ADBRootError, and ADBTimeoutError are treated
@@ -102,7 +103,7 @@ class ADBTimeoutError(Exception):
     pass
 
 
-class ADBCommand(object):
+class ADBCommand:
     """ADBCommand provides a basic interface to adb commands
     which is used to provide the 'command' methods for the
     classes ADBHost and ADBDevice.
@@ -119,7 +120,7 @@ class ADBCommand(object):
        try:
            adbcommand = ADBCommand()
        except NotImplementedError:
-           print "ADBCommand can not be instantiated."
+           print("ADBCommand can not be instantiated.")
     """
 
     def __init__(self,
@@ -153,7 +154,7 @@ class ADBCommand(object):
         self._polling_interval = 0.1
         self._adb_version = ''
 
-        self._logger.debug("%s: %s" % (self.__class__.__name__,
+        self._logger.debug("{}: {}".format(self.__class__.__name__,
                                        self.__dict__))
 
         # catch early a missing or non executable adb command
@@ -165,7 +166,7 @@ class ADBCommand(object):
             re_version = re.compile(r'Android Debug Bridge version (.*)')
             self._adb_version = re_version.match(output[0]).group(1)
         except Exception as exc:
-            raise ADBError('%s: %s is not executable.' % (exc, adb))
+            raise ADBError('{}: {} is not executable.'.format(exc, adb))
 
     def _get_logger(self, logger_name):
         logger = None
@@ -491,13 +492,12 @@ class ADBHost(ADBCommand):
         return devices
 
 
-class ADBDevice(ADBCommand):
+class ADBDevice(six.with_metaclass(ABCMeta, ADBCommand)):
     """ADBDevice is an abstract base class which provides methods which
     can be used to interact with the associated Android or B2G based
     device. It must be used via one of the concrete implementations in
     :class:`ADBAndroid` or :class:`ADBB2G`.
     """
-    __metaclass__ = ABCMeta
 
     def __init__(self,
                  device=None,
@@ -645,7 +645,7 @@ class ADBDevice(ADBCommand):
         def is_valid_serial(serial):
             return ":" not in serial or serial.startswith("usb:")
 
-        if isinstance(device, (str, unicode)):
+        if isinstance(device, (str, str)):
             # Treat this as a device serial
             if not is_valid_serial(device):
                 raise ValueError("Device serials containing ':' characters are "
@@ -1034,10 +1034,10 @@ class ADBDevice(ADBCommand):
 
         # prepend cwd and env to command if necessary
         if cwd:
-            cmd = "cd %s && %s" % (cwd, cmd)
+            cmd = "cd {} && {}".format(cwd, cmd)
         if env:
-            envstr = '&& '.join(map(lambda x: 'export %s=%s' %
-                                    (x[0], x[1]), env.iteritems()))
+            envstr = '&& '.join(['export %s=%s' %
+                                    (x[0], x[1]) for x in env.items()])
             cmd = envstr + "&& " + cmd
         cmd += "; echo rc=$?"
 
@@ -1160,10 +1160,10 @@ class ADBDevice(ADBCommand):
     # Informational methods
 
     def _get_logcat_buffer_args(self, buffers):
-        valid_buffers = set(['radio', 'main', 'events'])
+        valid_buffers = {'radio', 'main', 'events'}
         invalid_buffers = set(buffers).difference(valid_buffers)
         if invalid_buffers:
-            raise ADBError('Invalid logcat buffers %s not in %s ' % (
+            raise ADBError('Invalid logcat buffers {} not in {} '.format(
                 list(invalid_buffers), list(valid_buffers)))
         args = []
         for b in buffers:
@@ -1436,13 +1436,13 @@ class ADBDevice(ADBCommand):
         self._logger.debug('chmod: path=%s, recursive=%s, mask=%s, root=%s' %
                            (path, recursive, mask, root))
         if not recursive:
-            self.shell_output("chmod %s %s" % (mask, path),
+            self.shell_output("chmod {} {}".format(mask, path),
                               timeout=timeout, root=root)
             return
 
         if self._chmod_R:
             try:
-                self.shell_output("chmod -R %s %s" % (mask, path),
+                self.shell_output("chmod -R {} {}".format(mask, path),
                                   timeout=timeout, root=root)
             except ADBError as e:
                 if e.message.find('No such file or directory') == -1:
@@ -1460,7 +1460,7 @@ class ADBDevice(ADBCommand):
         try:
             tmpf = tempfile.NamedTemporaryFile(delete=False)
             for entry in entries:
-                tmpf.write('chmod %s %s\n' % (mask, entry))
+                tmpf.write('chmod {} {}\n'.format(mask, entry))
             tmpf.close()
             chmodsh = '/data/local/tmp/%s' % os.path.basename(tmpf.name)
             self.push(tmpf.name, chmodsh)
@@ -1560,7 +1560,7 @@ class ADBDevice(ADBCommand):
         data = []
         if self.is_dir(path, timeout=timeout, root=root):
             try:
-                data = self.shell_output("%s %s" % (self._ls, path),
+                data = self.shell_output("{} {}".format(self._ls, path),
                                          timeout=timeout,
                                          root=root).split('\r\n')
                 self._logger.debug('list_files: data: %s' % data)
@@ -1632,7 +1632,7 @@ class ADBDevice(ADBCommand):
                                           root=root)
                 if model == 'Nexus 4':
                     path += '*'
-        lines = self.shell_output('%s %s %s' % (self._ls, recursive_flag, path),
+        lines = self.shell_output('{} {} {}'.format(self._ls, recursive_flag, path),
                                   timeout=timeout,
                                   root=root).split('\r\n')
         for line in lines:
@@ -1647,11 +1647,11 @@ class ADBDevice(ADBCommand):
                 if parent[:-1] in entries:
                     del entries[parent[:-1]]
             elif parent:
-                entry = "%s%s" % (parent, line)
+                entry = "{}{}".format(parent, line)
             else:
                 entry = line
             entries[entry] = 1
-        entry_list = entries.keys()
+        entry_list = list(entries.keys())
         entry_list.sort()
         return entry_list
 
@@ -1841,7 +1841,7 @@ class ADBDevice(ADBCommand):
         if recursive:
             cmd += " -r"
         try:
-            self.shell_output("%s %s" % (cmd, path), timeout=timeout, root=root)
+            self.shell_output("{} {}".format(cmd, path), timeout=timeout, root=root)
             if self.is_file(path, timeout=timeout, root=root):
                 raise ADBError('rm("%s") failed to remove file.' % path)
         except ADBError as e:
@@ -1907,7 +1907,7 @@ class ADBDevice(ADBCommand):
                     pid_i = i
             if user_i == -1 or pid_i == -1:
                 self._logger.error('get_process_list: %s' % header)
-                raise ADBError('get_process_list: Unknown format: %s: %s' % (
+                raise ADBError('get_process_list: Unknown format: {}: {}'.format(
                     header, adb_process))
             ret = []
             line = adb_process.stdout_file.readline()
@@ -1916,9 +1916,9 @@ class ADBDevice(ADBCommand):
                 try:
                     ret.append([int(els[pid_i]), els[-1], els[user_i]])
                 except ValueError:
-                    self._logger.error('get_process_list: %s %s\n%s' % (
+                    self._logger.error('get_process_list: {} {}\n{}'.format(
                         header, line, traceback.format_exc()))
-                    raise ADBError('get_process_list: %s: %s: %s' % (
+                    raise ADBError('get_process_list: {}: {}: {}'.format(
                         header, line, adb_process))
                 line = adb_process.stdout_file.readline()
             self._logger.debug('get_process_list: %s' % ret)
@@ -1962,8 +1962,8 @@ class ADBDevice(ADBCommand):
                 if 'No such process' not in e.message:
                     raise
             pid_set = set(pid_list)
-            current_pid_set = set([str(proc[0]) for proc in
-                                   self.get_process_list(timeout=timeout)])
+            current_pid_set = {str(proc[0]) for proc in
+                                   self.get_process_list(timeout=timeout)}
             pid_list = list(pid_set.intersection(current_pid_set))
             if not pid_list:
                 break
@@ -2033,7 +2033,7 @@ class ADBDevice(ADBCommand):
         :raises: * ADBTimeoutError
                  * ADBError
         """
-        if not isinstance(process_name, basestring):
+        if not isinstance(process_name, str):
             raise ADBError("Process name %s is not a string" % process_name)
 
         # Filter out extra spaces.
@@ -2087,7 +2087,7 @@ class ADBDevice(ADBCommand):
         destination = posixpath.normpath(destination)
         if self._have_cp:
             r = '-R' if recursive else ''
-            self.shell_output('cp %s %s %s' % (r, source, destination),
+            self.shell_output('cp {} {} {}'.format(r, source, destination),
                               timeout=timeout, root=root)
             return
 
@@ -2102,7 +2102,7 @@ class ADBDevice(ADBCommand):
                 # Copy the source file into the destination directory
                 destination = posixpath.join(destination,
                                              posixpath.basename(source))
-            self.shell_output('dd if=%s of=%s' % (source, destination),
+            self.shell_output('dd if={} of={}'.format(source, destination),
                               timeout=timeout, root=root)
             return
 
@@ -2153,7 +2153,7 @@ class ADBDevice(ADBCommand):
         """
         source = posixpath.normpath(source)
         destination = posixpath.normpath(destination)
-        self.shell_output('mv %s %s' % (source, destination), timeout=timeout,
+        self.shell_output('mv {} {}'.format(source, destination), timeout=timeout,
                           root=root)
 
     def reboot(self, timeout=None):
diff --git a/testing/mozbase/mozdevice/mozdevice/adb_android.py b/testing/mozbase/mozdevice/mozdevice/adb_android.py
index bf5fffc0e5..51f4fcd82a 100644
--- a/testing/mozbase/mozdevice/mozdevice/adb_android.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb_android.py
@@ -8,12 +8,13 @@ import time
 
 from abc import ABCMeta
 
-import version_codes
+from . import version_codes
 
-from adb import ADBDevice, ADBError
+from .adb import ADBDevice, ADBError
+import six
 
 
-class ADBAndroid(ADBDevice):
+class ADBAndroid(six.with_metaclass(ABCMeta, ADBDevice)):
     """ADBAndroid implements :class:`ADBDevice` providing Android-specific
     functionality.
 
@@ -22,11 +23,10 @@ class ADBAndroid(ADBDevice):
        from mozdevice import ADBAndroid
 
        adbdevice = ADBAndroid()
-       print adbdevice.list_files("/mnt/sdcard")
+       print(adbdevice.list_files("/mnt/sdcard"))
        if adbdevice.process_exist("org.mozilla.fennec"):
-           print "Fennec is running"
+           print("Fennec is running")
     """
-    __metaclass__ = ABCMeta
 
     def __init__(self,
                  device=None,
@@ -220,7 +220,7 @@ class ADBAndroid(ADBDevice):
                 failure = e.message
 
             if not success:
-                self._logger.debug('Attempt %s of %s device not ready: %s' % (
+                self._logger.debug('Attempt {} of {} device not ready: {}'.format(
                     attempt + 1, self._device_ready_retry_attempts,
                     failure))
                 time.sleep(self._device_ready_retry_wait)
@@ -333,13 +333,13 @@ class ADBAndroid(ADBDevice):
                            "at once")
 
         acmd = ["am", "start"] + \
-            ["-W" if wait else '', "-n", "%s/%s" % (app_name, activity_name)]
+            ["-W" if wait else '', "-n", "{}/{}".format(app_name, activity_name)]
 
         if intent:
             acmd.extend(["-a", intent])
 
         if extras:
-            for (key, val) in extras.iteritems():
+            for (key, val) in extras.items():
                 if isinstance(val, int):
                     extra_type_param = "--ei"
                 elif isinstance(val, bool):
@@ -389,7 +389,7 @@ class ADBAndroid(ADBDevice):
         if moz_env:
             # moz_env is expected to be a dictionary of environment variables:
             # Fennec itself will set them when launched
-            for (env_count, (env_key, env_val)) in enumerate(moz_env.iteritems()):
+            for (env_count, (env_key, env_val)) in enumerate(moz_env.items()):
                 extras["env" + str(env_count)] = env_key + "=" + env_val
 
         # Additional command line arguments that fennec will read and use (e.g.
@@ -465,7 +465,7 @@ class ADBAndroid(ADBDevice):
             data = self.command_output(["uninstall", app_name], timeout=timeout)
             if data.find('Success') == -1:
                 self._logger.debug('uninstall_app failed: %s' % data)
-                raise ADBError("uninstall failed for %s. Got: %s" % (app_name, data))
+                raise ADBError("uninstall failed for {}. Got: {}".format(app_name, data))
             if reboot:
                 self.reboot(timeout=timeout)
 
diff --git a/testing/mozbase/mozdevice/mozdevice/adb_b2g.py b/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
index 3280e61720..88226e551a 100644
--- a/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
@@ -6,7 +6,7 @@ import traceback
 
 import mozfile
 
-from adb import ADBDevice, ADBError
+from .adb import ADBDevice, ADBError
 
 
 class ADBB2G(ADBDevice):
@@ -18,9 +18,9 @@ class ADBB2G(ADBDevice):
        from mozdevice import ADBB2G
 
        adbdevice = ADBB2G()
-       print adbdevice.list_files("/mnt/sdcard")
+       print(adbdevice.list_files("/mnt/sdcard"))
        if adbdevice.process_exist("b2g"):
-           print "B2G is running"
+           print("B2G is running")
     """
 
     def get_battery_percentage(self, timeout=None):
@@ -96,7 +96,7 @@ class ADBB2G(ADBDevice):
         :raises: * ADBTimeoutError
                  * ADBError
         """
-        info = super(ADBB2G, self).get_info(directive=directive,
+        info = super().get_info(directive=directive,
                                             timeout=timeout)
 
         directives = ['memtotal']
diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanager.py b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
index de87735ef5..0f07880699 100644
--- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
@@ -27,8 +27,8 @@ class DMError(Exception):
 
 
 def abstractmethod(method):
-    line = method.func_code.co_firstlineno
-    filename = method.func_code.co_filename
+    line = method.__code__.co_firstlineno
+    filename = method.__code__.co_filename
 
     @wraps(method)
     def not_implemented(*args, **kwargs):
@@ -38,7 +38,7 @@ def abstractmethod(method):
     return not_implemented
 
 
-class DeviceManager(object):
+class DeviceManager:
     """
     Represents a connection to a device. Once an implementation of this class
     is successfully instantiated, you may do things like list/copy files to
@@ -250,7 +250,7 @@ class DeviceManager(object):
         Returns True if remoteDirname on device is same as localDirname on host.
         """
 
-        self._logger.info("validating directory: %s to %s" % (localDirname, remoteDirname))
+        self._logger.info("validating directory: {} to {}".format(localDirname, remoteDirname))
         for root, dirs, files in os.walk(localDirname):
             parts = root.split(localDirname)
             for f in files:
@@ -428,13 +428,13 @@ class DeviceManager(object):
         Information on process is in tuple format: (pid, process path, user)
         If a process with the specified name does not exist this function will return None.
         """
-        if not isinstance(processName, basestring):
+        if not isinstance(processName, str):
             raise TypeError("Process name %s is not a string" % processName)
 
         processInfo = None
 
         # filter out extra spaces
-        parts = filter(lambda x: x != '', processName.split(' '))
+        parts = [x for x in processName.split(' ') if x != '']
         processName = ' '.join(parts)
 
         # filter out the quoted env string if it exists
@@ -593,7 +593,7 @@ class DeviceManager(object):
         quotedCmd = []
 
         for arg in cmd:
-            arg.replace('&', '\&')
+            arg.replace('&', r'\&')
 
             needsQuoting = False
             for char in [' ', '(', ')', '"', '&']:
@@ -641,7 +641,7 @@ def _pop_last_line(file_obj):
     return None
 
 
-class ZeroconfListener(object):
+class ZeroconfListener:
 
     def __init__(self, hwid, evt):
         self.hwid = hwid
@@ -654,13 +654,13 @@ class ZeroconfListener(object):
             return
 
         sutname = name.split('.')[0]
-        m = re.search('\[hwid:([^\]]*)\]', sutname)
+        m = re.search(r'\[hwid:([^\]]*)\]', sutname)
         if m is None:
             return
 
         hwid = m.group(1)
 
-        m = re.search('\[ip:([0-9_]*)\]', sutname)
+        m = re.search(r'\[ip:([0-9_]*)\]', sutname)
         if m is None:
             return
 
diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
index 74d0a8d23f..ecfe430f99 100644
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -11,10 +11,10 @@ import traceback
 
 from distutils import dir_util
 
-from devicemanager import DeviceManager, DMError
+from .devicemanager import DeviceManager, DMError
 from mozprocess import ProcessHandler
 import mozfile
-import version_codes
+from . import version_codes
 
 
 class DeviceManagerADB(DeviceManager):
@@ -130,7 +130,7 @@ class DeviceManagerADB(DeviceManager):
         # doesn't actually return the return code from a process, so we have to
         # capture the output to get it
         if root and self._haveSu:
-            cmdline = "su %s \"%s\"" % (self._suModifier,
+            cmdline = "su {} \"{}\"".format(self._suModifier,
                                         self._escapedCommandLine(cmd))
         else:
             cmdline = self._escapedCommandLine(cmd)
@@ -138,9 +138,9 @@ class DeviceManagerADB(DeviceManager):
 
         # prepend cwd and env to command if necessary
         if cwd:
-            cmdline = "cd %s; %s" % (cwd, cmdline)
+            cmdline = "cd {}; {}".format(cwd, cmdline)
         if env:
-            envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
+            envstr = '; '.join(['export {}={}'.format(x[0], x[1]) for x in env.items()])
             cmdline = envstr + "; " + cmdline
 
         # all output should be in stdout
@@ -444,7 +444,7 @@ class DeviceManagerADB(DeviceManager):
         if env != '' and env is not None:
             envCnt = 0
             # env is expected to be a dict of environment variables
-            for envkey, envval in env.iteritems():
+            for envkey, envval in env.items():
                 acmd.append("--es")
                 acmd.append("env" + str(envCnt))
                 acmd.append(envkey + "=" + envval)
@@ -453,7 +453,7 @@ class DeviceManagerADB(DeviceManager):
             acmd.append("-d")
             acmd.append(uri)
 
-        acmd = ["shell", ' '.join(map(lambda x: '"' + x + '"', ["am", "start"] + acmd))]
+        acmd = ["shell", ' '.join(['"' + x + '"' for x in ["am", "start"] + acmd])]
         self._logger.info(acmd)
         self._checkCmd(acmd)
         return outputFile
@@ -494,7 +494,7 @@ class DeviceManagerADB(DeviceManager):
         try:
             self._runCmd(["pull",  remoteFile, localFile])
         except (OSError, ValueError):
-            raise DMError("Error pulling remote file '%s' to '%s'" % (remoteFile, localFile))
+            raise DMError("Error pulling remote file '{}' to '{}'".format(remoteFile, localFile))
 
     def pullFile(self, remoteFile, offset=None, length=None):
         # TODO: add debug flags and allow for printing stdout
@@ -628,7 +628,7 @@ class DeviceManagerADB(DeviceManager):
             uptime = self.shellCheckOutput(["uptime"], timeout=self.short_timeout)
             if not uptime:
                 raise DMError("error getting uptime")
-            m = re.match("up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})", uptime)
+            m = re.match(r"up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})", uptime)
             if m:
                 uptime = "%d days %d hours %d minutes %d seconds" % tuple(
                     [int(g or 0) for g in m.groups()[1:]])
@@ -654,7 +654,7 @@ class DeviceManagerADB(DeviceManager):
     def uninstallApp(self, appName, installPath=None):
         status = self._runCmd(["uninstall", appName]).output[0].strip()
         if status != 'Success':
-            raise DMError("uninstall failed for %s. Got: %s" % (appName, status))
+            raise DMError("uninstall failed for {}. Got: {}".format(appName, status))
 
     def uninstallAppAndReboot(self, appName, installPath=None):
         self.uninstallApp(appName)
@@ -769,7 +769,7 @@ class DeviceManagerADB(DeviceManager):
             proc = self._runCmd(["version"], timeout=self.short_timeout)
             self._adb_version = re_version.match(proc.output[0]).group(1)
             self._logger.info("Detected adb %s" % self._adb_version)
-        except os.error as err:
+        except OSError as err:
             raise DMError(
                 "unable to execute ADB (%s): ensure Android SDK is installed "
                 "and adb is in your $PATH" % err)
@@ -779,14 +779,14 @@ class DeviceManagerADB(DeviceManager):
         if self._deviceSerial:
             deviceStatus = None
             for line in self._runCmd(["devices"]).output:
-                m = re.match('(.+)?\s+(.+)$', line)
+                m = re.match(r'(.+)?\s+(.+)$', line)
                 if m:
                     if self._deviceSerial == m.group(1):
                         deviceStatus = m.group(2)
             if deviceStatus is None:
                 raise DMError("device not found: %s" % self._deviceSerial)
             elif deviceStatus != "device":
-                raise DMError("bad status for device %s: %s" % (self._deviceSerial, deviceStatus))
+                raise DMError("bad status for device {}: {}".format(self._deviceSerial, deviceStatus))
 
         # Check to see if we can connect to device and run a simple command
         if not self._checkCmd(["shell", "echo"], timeout=self.short_timeout) == 0:
diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py b/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
index 7816a3fdda..a1df5f7798 100644
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerSUT.py
@@ -13,7 +13,7 @@ import re
 import posixpath
 import subprocess
 import StringIO
-from devicemanager import DeviceManager, DMError, _pop_last_line
+from .devicemanager import DeviceManager, DMError, _pop_last_line
 import errno
 from distutils.version import StrictVersion
 
@@ -27,10 +27,10 @@ class DeviceManagerSUT(DeviceManager):
     """
 
     _base_prompt = '$>'
-    _base_prompt_re = '\$\>'
+    _base_prompt_re = r'\$\>'
     _prompt_sep = '\x00'
     _prompt_regex = '.*(' + _base_prompt_re + _prompt_sep + ')'
-    _agentErrorRE = re.compile('^##AGENT-WARNING##\ ?(.*)')
+    _agentErrorRE = re.compile(r'^##AGENT-WARNING##\ ?(.*)')
 
     reboot_timeout = 600
     reboot_settling_time = 60
@@ -47,7 +47,7 @@ class DeviceManagerSUT(DeviceManager):
 
         # Get version
         verstring = self._runCmds([{'cmd': 'ver'}])
-        ver_re = re.match('(\S+) Version (\S+)', verstring)
+        ver_re = re.match(r'(\S+) Version (\S+)', verstring)
         self.agentProductName = ver_re.group(1)
         self.agentVersion = ver_re.group(2)
 
@@ -167,7 +167,7 @@ class DeviceManagerSUT(DeviceManager):
                 if self._everConnected:
                     self._logger.info("reconnecting socket")
                 self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            except socket.error as msg:
+            except OSError as msg:
                 self._sock = None
                 raise DMError("Automation Error: unable to create socket: " + str(msg))
 
@@ -175,14 +175,14 @@ class DeviceManagerSUT(DeviceManager):
                 self._sock.settimeout(float(timeout))
                 self._sock.connect((self.host, int(self.port)))
                 self._everConnected = True
-            except socket.error as msg:
+            except OSError as msg:
                 self._sock = None
                 raise DMError("Remote Device Error: Unable to connect socket: " + str(msg))
 
             # consume prompt
             try:
                 self._sock.recv(1024)
-            except socket.error as msg:
+            except OSError as msg:
                 self._sock.close()
                 self._sock = None
                 raise DMError(
@@ -210,7 +210,7 @@ class DeviceManagerSUT(DeviceManager):
                         totalsent += sent
 
                 self._logger.debug("sent cmd: %s" % cmd['cmd'])
-            except socket.error as msg:
+            except OSError as msg:
                 self._sock.close()
                 self._sock = None
                 self._logger.error("Remote Device Error: Error sending data"
@@ -239,7 +239,7 @@ class DeviceManagerSUT(DeviceManager):
                         # Wait up to a second for socket to become ready for reading...
                         if select.select([self._sock], [], [], select_timeout)[0]:
                             temp = self._sock.recv(1024)
-                            self._logger.debug(u"response: %s" % temp.decode('utf8', 'replace'))
+                            self._logger.debug("response: %s" % temp.decode('utf8', 'replace'))
                             timer = 0
                             if not temp:
                                 socketClosed = True
@@ -250,7 +250,7 @@ class DeviceManagerSUT(DeviceManager):
                             self._sock = None
                             raise DMError("Automation Error: Timeout in command %s" %
                                           cmd['cmd'], fatal=True)
-                    except socket.error as err:
+                    except OSError as err:
                         socketClosed = True
                         errStr = str(err)
                         # This error shows up with we have our tegra rebooted.
@@ -313,7 +313,7 @@ class DeviceManagerSUT(DeviceManager):
     def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
         cmdline = self._escapedCommandLine(cmd)
         if env:
-            cmdline = '%s %s' % (self._formatEnvString(env), cmdline)
+            cmdline = '{} {}'.format(self._formatEnvString(env), cmdline)
 
         # execcwd/execcwdsu currently unsupported in Negatus; see bug 824127.
         if cwd and self.agentProductName == 'SUTAgentNegatus':
@@ -335,22 +335,22 @@ class DeviceManagerSUT(DeviceManager):
             cmd += "su"
 
         if cwd:
-            self._sendCmds([{'cmd': '%s %s %s' % (cmd, cwd, cmdline)}], outputfile, timeout)
+            self._sendCmds([{'cmd': '{} {} {}'.format(cmd, cwd, cmdline)}], outputfile, timeout)
         else:
             if (not root) or haveExecSu:
-                self._sendCmds([{'cmd': '%s %s' % (cmd, cmdline)}], outputfile, timeout)
+                self._sendCmds([{'cmd': '{} {}'.format(cmd, cmdline)}], outputfile, timeout)
             else:
                 # need to manually inject su -c for backwards compatibility (this may
                 # not work on ICS or above!!)
                 # (FIXME: this backwards compatibility code is really ugly and should
                 # be deprecated at some point in the future)
-                self._sendCmds([{'cmd': '%s su -c "%s"' % (cmd, cmdline)}], outputfile,
+                self._sendCmds([{'cmd': '{} su -c "{}"'.format(cmd, cmdline)}], outputfile,
                                timeout)
 
         # dig through the output to get the return code
         lastline = _pop_last_line(outputfile)
         if lastline:
-            m = re.search('return code \[([0-9]+)\]', lastline)
+            m = re.search(r'return code \[([0-9]+)\]', lastline)
             if m:
                 return int(m.group(1))
 
@@ -385,7 +385,7 @@ class DeviceManagerSUT(DeviceManager):
 
     def pushDir(self, localDir, remoteDir, retryLimit=None, timeout=None):
         retryLimit = retryLimit or self.retryLimit
-        self._logger.info("pushing directory: %s to %s" % (localDir, remoteDir))
+        self._logger.info("pushing directory: {} to {}".format(localDir, remoteDir))
 
         existentDirectories = []
         for root, dirs, files in os.walk(localDir, followlinks=True):
@@ -430,7 +430,7 @@ class DeviceManagerSUT(DeviceManager):
             return []
         data = self._runCmds([{'cmd': 'cd ' + rootdir}, {'cmd': 'ls'}])
 
-        files = filter(lambda x: x, data.splitlines())
+        files = [x for x in data.splitlines() if x]
         if len(files) == 1 and files[0] == '<empty>':
             # special case on the agent: empty directories return just the
             # string "<empty>"
@@ -447,10 +447,10 @@ class DeviceManagerSUT(DeviceManager):
             self._runCmds([{'cmd': 'rmdr ' + remoteDir}])
 
     def moveTree(self, source, destination):
-        self._runCmds([{'cmd': 'mv %s %s' % (source, destination)}])
+        self._runCmds([{'cmd': 'mv {} {}'.format(source, destination)}])
 
     def copyTree(self, source, destination):
-        self._runCmds([{'cmd': 'dd if=%s of=%s' % (source, destination)}])
+        self._runCmds([{'cmd': 'dd if={} of={}'.format(source, destination)}])
 
     def getProcessList(self):
         data = self._runCmds([{'cmd': 'ps'}])
@@ -470,7 +470,7 @@ class DeviceManagerSUT(DeviceManager):
                         raise ValueError
                 except ValueError:
                     self._logger.error("Unable to parse process list (bug 805969)")
-                    self._logger.error("Line: %s\nFull output of process list:\n%s" % (line, data))
+                    self._logger.error("Line: {}\nFull output of process list:\n{}".format(line, data))
                     raise DMError("Invalid process line: %s" % line)
 
         return processTuples
@@ -508,7 +508,7 @@ class DeviceManagerSUT(DeviceManager):
             time.sleep(1)
             waited += 1
 
-        self._logger.debug("got pid: %s for process: %s" % (pid, appname))
+        self._logger.debug("got pid: {} for process: {}".format(pid, appname))
         return pid
 
     def launchProcess(self, cmd, outputFile="process.txt", cwd='', env='', failIfRunning=False):
@@ -535,7 +535,7 @@ class DeviceManagerSUT(DeviceManager):
             cmdline += " > " + outputFile
 
         # Prepend our env to the command
-        cmdline = '%s %s' % (self._formatEnvString(env), cmdline)
+        cmdline = '{} {}'.format(self._formatEnvString(env), cmdline)
 
         # fireProcess may trigger an exception, but we won't handle it
         if cmd[0] == "am":
@@ -740,7 +740,7 @@ class DeviceManagerSUT(DeviceManager):
         if destDir[-1] != '/':
             destDir += '/'
 
-        self._runCmds([{'cmd': 'unzp %s %s' % (filePath, destDir)}])
+        self._runCmds([{'cmd': 'unzp {} {}'.format(filePath, destDir)}])
 
     def _getRebootServerSocket(self, ipAddr):
         serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -770,7 +770,7 @@ class DeviceManagerSUT(DeviceManager):
                 conn.close()
             except socket.timeout:
                 pass
-            except socket.error as e:
+            except OSError as e:
                 if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
                     raise
 
@@ -803,7 +803,7 @@ class DeviceManagerSUT(DeviceManager):
             # after restarting.
             destname = '/data/data/com.mozilla.SUTAgentAndroid/files/update.info'
             data = "%s,%s\rrebooting\r" % serverSocket.getsockname()
-            self._runCmds([{'cmd': 'push %s %s' % (destname, len(data)),
+            self._runCmds([{'cmd': 'push {} {}'.format(destname, len(data)),
                             'data': data}])
             cmd += " %s %s" % serverSocket.getsockname()
 
@@ -832,8 +832,8 @@ class DeviceManagerSUT(DeviceManager):
             result[d] = data.split('\n')
 
         # Get rid of any 0 length members of the arrays
-        for k, v in result.iteritems():
-            result[k] = filter(lambda x: x != '', result[k])
+        for k, v in result.items():
+            result[k] = [x for x in result[k] if x != '']
 
         # Format the process output
         if 'process' in result:
@@ -920,7 +920,7 @@ class DeviceManagerSUT(DeviceManager):
         if (env is None or env == ''):
             return ''
 
-        retVal = '"%s"' % ','.join(map(lambda x: '%s=%s' % (x[0], x[1]), env.iteritems()))
+        retVal = '"%s"' % ','.join(['{}={}'.format(x[0], x[1]) for x in env.items()])
         if (retVal == '""'):
             return ''
 
@@ -964,12 +964,12 @@ class DeviceManagerSUT(DeviceManager):
         if (height < 100 or height > 9999):
             return False
 
-        self._logger.debug("adjusting screen resolution to %s, %s and rebooting" % (width, height))
+        self._logger.debug("adjusting screen resolution to {}, {} and rebooting".format(width, height))
 
         self._runCmds(
-            [{'cmd': "exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width)}])
+            [{'cmd': "exec setprop persist.tegra.dpy{}.mode.width {}".format(screentype, width)}])
         self._runCmds(
-            [{'cmd': "exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height)}])
+            [{'cmd': "exec setprop persist.tegra.dpy{}.mode.height {}".format(screentype, height)}])
 
     def chmodDir(self, remoteDir, **kwargs):
         self._runCmds([{'cmd': "chmod " + remoteDir}])
diff --git a/testing/mozbase/mozdevice/mozdevice/dmcli.py b/testing/mozbase/mozdevice/mozdevice/dmcli.py
index 7ba65e8426..f9d13ea23b 100644
--- a/testing/mozbase/mozdevice/mozdevice/dmcli.py
+++ b/testing/mozbase/mozdevice/mozdevice/dmcli.py
@@ -6,6 +6,7 @@
 Command-line client to control a device
 """
 
+from __future__ import print_function
 import errno
 import logging
 import os
@@ -190,7 +191,7 @@ class DMCli(object):
 
     def add_commands(self, parser):
         subparsers = parser.add_subparsers(title="Commands", metavar="<command>")
-        for (commandname, commandprops) in sorted(self.commands.iteritems()):
+        for (commandname, commandprops) in sorted(self.commands.items()):
             subparser = subparsers.add_parser(commandname, help=commandprops['help'])
             if commandprops.get('args'):
                 for arg in commandprops['args']:
@@ -234,7 +235,7 @@ class DMCli(object):
             self.parser.error("Unknown device manager type: %s" % type)
 
     def deviceroot(self, args):
-        print self.dm.deviceRoot
+        print(self.dm.deviceRoot)
 
     def push(self, args):
         (src, dest) = (args.local_file, args.remote_file)
@@ -250,7 +251,7 @@ class DMCli(object):
     def pull(self, args):
         (src, dest) = (args.local_file, args.remote_file)
         if not self.dm.fileExists(src):
-            print 'No such file or directory'
+            print('No such file or directory')
             return
         if not dest:
             dest = posixpath.basename(src)
@@ -276,7 +277,7 @@ class DMCli(object):
 
     def listapps(self, args):
         for app in self.dm.getInstalledApps():
-            print app
+            print(app)
 
     def stopapp(self, args):
         self.dm.stopApplication(args.appname)
@@ -288,20 +289,20 @@ class DMCli(object):
     def shell(self, args):
         buf = StringIO.StringIO()
         self.dm.shell(args.command, buf, root=args.root)
-        print str(buf.getvalue()[0:-1]).rstrip()
+        print(str(buf.getvalue()[0:-1]).rstrip())
 
     def getinfo(self, args):
         info = self.dm.getInfo(directive=args.directive)
-        for (infokey, infoitem) in sorted(info.iteritems()):
+        for (infokey, infoitem) in sorted(info.items()):
             if infokey == "process":
                 pass  # skip process list: get that through ps
             elif args.directive is None:
-                print "%s: %s" % (infokey.upper(), infoitem)
+                print("%s: %s" % (infokey.upper(), infoitem))
             else:
-                print infoitem
+                print(infoitem)
 
     def logcat(self, args):
-        print ''.join(self.dm.getLogcat())
+        print(''.join(self.dm.getLogcat()))
 
     def clearlogcat(self, args):
         self.dm.recordLogcat()
@@ -312,22 +313,22 @@ class DMCli(object):
     def processlist(self, args):
         pslist = self.dm.getProcessList()
         for ps in pslist:
-            print " ".join(str(i) for i in ps)
+            print(" ".join(str(i) for i in ps))
 
     def listfiles(self, args):
         filelist = self.dm.listFiles(args.remote_dir)
         for file in filelist:
-            print file
+            print(file)
 
     def removefile(self, args):
         self.dm.removeFile(args.remote_file)
 
     def isdir(self, args):
         if self.dm.dirExists(args.remote_dir):
-            print "TRUE"
+            print("TRUE")
             return
 
-        print "FALSE"
+        print("FALSE")
         return errno.ENOTDIR
 
     def mkdir(self, args):
@@ -341,16 +342,16 @@ class DMCli(object):
 
     def sutver(self, args):
         if args.dmtype == 'sut':
-            print '%s Version %s' % (self.dm.agentProductName,
-                                     self.dm.agentVersion)
+            print('%s Version %s' % (self.dm.agentProductName,
+                                     self.dm.agentVersion))
         else:
-            print 'Must use SUT transport to get SUT version.'
+            print('Must use SUT transport to get SUT version.')
 
     def isfile(self, args):
         if self.dm.fileExists(args.remote_file):
-            print "TRUE"
+            print("TRUE")
             return
-        print "FALSE"
+        print("FALSE")
         return errno.ENOENT
 
     def launchfennec(self, args):
@@ -368,9 +369,9 @@ class DMCli(object):
 
     def getip(self, args):
         if args.interface:
-            print(self.dm.getIP(args.interface))
+            print((self.dm.getIP(args.interface)))
         else:
-            print(self.dm.getIP())
+            print((self.dm.getIP()))
 
 
 def cli(args=sys.argv[1:]):
diff --git a/testing/mozbase/mozdevice/mozdevice/droid.py b/testing/mozbase/mozdevice/mozdevice/droid.py
index f06a619c44..3f9f138d32 100644
--- a/testing/mozbase/mozdevice/mozdevice/droid.py
+++ b/testing/mozbase/mozdevice/mozdevice/droid.py
@@ -2,19 +2,20 @@
 # 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 print_function
 import StringIO
 import moznetwork
 import re
 import threading
 import time
 
-import version_codes
+from . import version_codes
 
-from Zeroconf import Zeroconf, ServiceBrowser
-from devicemanager import ZeroconfListener
-from devicemanagerADB import DeviceManagerADB
-from devicemanagerSUT import DeviceManagerSUT
-from devicemanager import DMError
+from .Zeroconf import Zeroconf, ServiceBrowser
+from .devicemanager import ZeroconfListener
+from .devicemanagerADB import DeviceManagerADB
+from .devicemanagerSUT import DeviceManagerSUT
+from .devicemanager import DMError
 
 
 class DroidMixin(object):
@@ -54,7 +55,7 @@ class DroidMixin(object):
             acmd.extend(["-a", intent])
 
         if extras:
-            for (key, val) in extras.iteritems():
+            for (key, val) in extras.items():
                 if type(val) is int:
                     extraTypeParam = "--ei"
                 elif type(val) is bool:
@@ -96,7 +97,7 @@ class DroidMixin(object):
         if mozEnv:
             # mozEnv is expected to be a dictionary of environment variables: Fennec
             # itself will set them when launched
-            for (envCnt, (envkey, envval)) in enumerate(mozEnv.iteritems()):
+            for (envCnt, (envkey, envval)) in enumerate(mozEnv.items()):
                 extras["env" + str(envCnt)] = envkey + "=" + envval
 
         # Additional command line arguments that fennec will read and use (e.g.
@@ -181,7 +182,7 @@ class DroidADB(DeviceManagerADB, DroidMixin):
         if m:
             line = m.group(0)
             # Extract package name: string of non-whitespace ending in forward slash
-            m = re.search('(\S+)/$', line)
+            m = re.search(r'(\S+)/$', line)
             if m:
                 package = m.group(1)
         if not package:
@@ -251,7 +252,7 @@ def DroidConnectByHWID(hwid, timeout=30, **kwargs):
 
     if foundIP is not None:
         return DroidSUT(foundIP, **kwargs)
-    print "Connected via SUT to %s [at %s]" % (hwid, foundIP)
+    print("Connected via SUT to %s [at %s]" % (hwid, foundIP))
 
     # try connecting via adb
     try:
@@ -259,5 +260,5 @@ def DroidConnectByHWID(hwid, timeout=30, **kwargs):
     except:
         return None
 
-    print "Connected via ADB to %s" % (hwid)
+    print("Connected via ADB to %s" % (hwid))
     return sut
diff --git a/testing/mozbase/mozdevice/mozdevice/sutini.py b/testing/mozbase/mozdevice/mozdevice/sutini.py
index 7dd5e54c4a..e9cb725b52 100644
--- a/testing/mozbase/mozdevice/mozdevice/sutini.py
+++ b/testing/mozbase/mozdevice/mozdevice/sutini.py
@@ -2,7 +2,8 @@
 # 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/.
 
-import ConfigParser
+from __future__ import print_function
+import six.moves.configparser
 import StringIO
 import os
 import sys
@@ -10,6 +11,7 @@ import tempfile
 
 from mozdevice.droid import DroidSUT
 from mozdevice.devicemanager import DMError
+import six
 
 USAGE = '%s <host>'
 INI_PATH_JAVA = '/data/data/com.mozilla.SUTAgentAndroid/files/SUTAgent.ini'
@@ -25,7 +27,7 @@ SCHEMA = {'Registration Server': (('IPAddr', ''),
 
 
 def get_cfg(d, ini_path):
-    cfg = ConfigParser.RawConfigParser()
+    cfg = six.moves.configparser.RawConfigParser()
     try:
         cfg.readfp(StringIO.StringIO(d.pullFile(ini_path)), 'SUTAgent.ini')
     except DMError:
@@ -35,16 +37,16 @@ def get_cfg(d, ini_path):
 
 
 def put_cfg(d, cfg, ini_path):
-    print 'Writing modified SUTAgent.ini...'
+    print('Writing modified SUTAgent.ini...')
     t = tempfile.NamedTemporaryFile(delete=False)
     cfg.write(t)
     t.close()
     try:
         d.pushFile(t.name, ini_path)
-    except DMError, e:
-        print e
+    except DMError as e:
+        print(e)
     else:
-        print 'Done.'
+        print('Done.')
     finally:
         os.unlink(t.name)
 
@@ -53,14 +55,14 @@ def set_opt(cfg, s, o, dflt):
     prompt = '  %s' % o
     try:
         curval = cfg.get(s, o)
-    except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+    except (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
         curval = ''
     if curval:
         dflt = curval
     prompt += ': '
     if dflt:
         prompt += '[%s] ' % dflt
-    newval = raw_input(prompt)
+    newval = input(prompt)
     if not newval:
         newval = dflt
     if newval == curval:
@@ -71,10 +73,10 @@ def set_opt(cfg, s, o, dflt):
 
 def bool_query(prompt, dflt):
     while True:
-        i = raw_input('%s [%s] ' % (prompt, 'y' if dflt else 'n')).lower()
+        i = input('%s [%s] ' % (prompt, 'y' if dflt else 'n')).lower()
         if not i or i[0] in ('y', 'n'):
             break
-        print 'Enter y or n.'
+        print('Enter y or n.')
     return (not i and dflt) or (i and i[0] == 'y')
 
 
@@ -83,10 +85,10 @@ def edit_sect(cfg, sect, opts):
     if bool_query('Edit section %s?' % sect, False):
         if not cfg.has_section(sect):
             cfg.add_section(sect)
-        print '%s settings:' % sect
+        print('%s settings:' % sect)
         for opt, dflt in opts:
             changed_vals |= set_opt(cfg, sect, opt, dflt)
-        print
+        print()
     else:
         if cfg.has_section(sect) and bool_query('Delete section %s?' % sect,
                                                 False):
@@ -99,12 +101,12 @@ def main():
     try:
         host = sys.argv[1]
     except IndexError:
-        print USAGE % sys.argv[0]
+        print(USAGE % sys.argv[0])
         sys.exit(1)
     try:
         d = DroidSUT(host, retryLimit=1)
-    except DMError, e:
-        print e
+    except DMError as e:
+        print(e)
         sys.exit(1)
     # check if using Negatus and change path accordingly
     ini_path = INI_PATH_JAVA
@@ -112,14 +114,14 @@ def main():
         ini_path = INI_PATH_NEGATUS
     cfg = get_cfg(d, ini_path)
     if not cfg.sections():
-        print 'Empty or missing ini file.'
+        print('Empty or missing ini file.')
     changed_vals = False
-    for sect, opts in SCHEMA.iteritems():
+    for sect, opts in SCHEMA.items():
         changed_vals |= edit_sect(cfg, sect, opts)
     if changed_vals:
         put_cfg(d, cfg, ini_path)
     else:
-        print 'No changes.'
+        print('No changes.')
 
 
 if __name__ == '__main__':
diff --git a/testing/mozbase/mozdevice/sut_tests/dmunit.py b/testing/mozbase/mozdevice/sut_tests/dmunit.py
index b4a3d0b9ba..94cb17b3f1 100644
--- a/testing/mozbase/mozdevice/sut_tests/dmunit.py
+++ b/testing/mozbase/mozdevice/sut_tests/dmunit.py
@@ -48,7 +48,7 @@ class DeviceManagerTestLoader(unittest.TestLoader):
         module = __import__(module_name)
         for name in dir(module):
             obj = getattr(module, name)
-            if (isinstance(obj, (type, types.ClassType)) and
+            if (isinstance(obj, (type, type)) and
                     issubclass(obj, unittest.TestCase)) and \
                     (not self.isTestDevice or obj.runs_on_test_device):
                 tests.append(self.loadTestsFromTestCase(obj))
diff --git a/testing/mozbase/mozdevice/sut_tests/genfiles.py b/testing/mozbase/mozdevice/sut_tests/genfiles.py
index 5ab8d6349e..b4014a600b 100644
--- a/testing/mozbase/mozdevice/sut_tests/genfiles.py
+++ b/testing/mozbase/mozdevice/sut_tests/genfiles.py
@@ -11,7 +11,7 @@ import shutil
 
 def gen_binary_file(path, size):
     with open(path, 'wb') as f:
-        for i in xrange(size):
+        for i in range(size):
             byte = '%c' % randint(0, 255)
             f.write(byte)
 
diff --git a/testing/mozbase/mozdevice/sut_tests/runtests.py b/testing/mozbase/mozdevice/sut_tests/runtests.py
index fffc306e3e..b03be7d6d7 100644
--- a/testing/mozbase/mozdevice/sut_tests/runtests.py
+++ b/testing/mozbase/mozdevice/sut_tests/runtests.py
@@ -2,6 +2,7 @@
 # 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 print_function
 from optparse import OptionParser
 import logging
 import os
@@ -27,11 +28,11 @@ def main(ip, port, heartbeat_port, scripts, directory, isTestDevice, verbose):
     if scripts:
         # Ensure the user didn't include the .py on the name of the test file
         # (and get rid of it if they did)
-        scripts = map(lambda x: x.split('.')[0], scripts)
+        scripts = [x.split('.')[0] for x in scripts]
     else:
         # Go through the directory and pick up everything
         # named test_*.py and run it
-        testfile = re.compile('^test_.*\.py$')
+        testfile = re.compile(r'^test_.*\.py$')
         files = os.listdir(directory)
 
         for f in files:
@@ -56,7 +57,7 @@ if __name__ == "__main__":
         try:
             env_port = int(env_port)
         except ValueError:
-            print >> sys.stderr, "Port in TEST_DEVICE should be an integer."
+            print("Port in TEST_DEVICE should be an integer.", file=sys.stderr)
             sys.exit(1)
 
     # Deal with the options
diff --git a/testing/mozbase/mozdevice/sut_tests/test_datachannel.py b/testing/mozbase/mozdevice/sut_tests/test_datachannel.py
index 99b71a584d..680ec45dfb 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_datachannel.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_datachannel.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import re
 import socket
 from time import strptime
@@ -30,7 +31,7 @@ class DataChannelTestCase(DeviceManagerTestCase):
         capturedHeader = False
         while numbeats < 3:
             data = self._datasock.recv(1024)
-            print data
+            print(data)
             self.assertNotEqual(len(data), 0)
 
             # Check for the header
diff --git a/testing/mozbase/mozdevice/sut_tests/test_getdir.py b/testing/mozbase/mozdevice/sut_tests/test_getdir.py
index 00ea8c9ae3..66a0694af7 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_getdir.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_getdir.py
@@ -18,7 +18,7 @@ class GetDirectoryTestCase(DeviceManagerTestCase):
         os.makedirs(os.path.join(self.localsrcdir, 'push1', 'sub.1', 'sub.2'))
         path = os.path.join(self.localsrcdir,
                             'push1', 'sub.1', 'sub.2', 'testfile')
-        file(path, 'w').close()
+        open(path, 'w').close()
         os.makedirs(os.path.join(self.localsrcdir, 'push1', 'emptysub'))
         self.localdestdir = tempfile.mkdtemp()
         self.expected_filelist = ['emptysub', 'sub.1']
diff --git a/testing/mozbase/mozdevice/sut_tests/test_info.py b/testing/mozbase/mozdevice/sut_tests/test_info.py
index 57bb4fce01..54a96e65b0 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_info.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_info.py
@@ -2,6 +2,7 @@
 # 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 print_function
 from dmunit import DeviceManagerTestCase
 
 
@@ -15,6 +16,6 @@ class InfoTestCase(DeviceManagerTestCase):
         cmds = ('os', 'id', 'systime', 'uptime', 'screen', 'memory', 'power')
         for c in cmds:
             data = self.dm.getInfo(c)
-            print c + str(data)
+            print(c + str(data))
 
         # No real good way to verify this.  If it doesn't throw, we're ok.
diff --git a/testing/mozbase/mozdevice/sut_tests/test_prompt.py b/testing/mozbase/mozdevice/sut_tests/test_prompt.py
index 9980ee2ab9..dde349fc68 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_prompt.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_prompt.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import re
 import socket
 
@@ -21,10 +22,10 @@ class PromptTestCase(DeviceManagerTestCase):
         ip = self.dm.host
         port = self.dm.port
 
-        promptre = re.compile('.*\$\>\x00')
+        promptre = re.compile('.*\\$\\>\x00')
         data = ""
         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         self.sock.connect((ip, int(port)))
         data = self.sock.recv(1024)
-        print data
+        print(data)
         self.assertTrue(promptre.match(data))
diff --git a/testing/mozbase/mozdevice/sut_tests/test_pull.py b/testing/mozbase/mozdevice/sut_tests/test_pull.py
index 753d8ddd53..81e4dd4d86 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_pull.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_pull.py
@@ -18,7 +18,7 @@ class PullTestCase(DeviceManagerTestCase):
         orig = hashlib.md5()
         new = hashlib.md5()
         local_test_file = os.path.join('test-files', 'mybinary.zip')
-        orig.update(file(local_test_file, 'r').read())
+        orig.update(open(local_test_file, 'r').read())
 
         testroot = self.dm.deviceRoot
         remote_test_file = posixpath.join(testroot, 'mybinary.zip')
diff --git a/testing/mozbase/mozdevice/sut_tests/test_push1.py b/testing/mozbase/mozdevice/sut_tests/test_push1.py
index f457d6cc55..8859ad9496 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_push1.py
+++ b/testing/mozbase/mozdevice/sut_tests/test_push1.py
@@ -28,7 +28,7 @@ class Push1TestCase(DeviceManagerTestCase):
         if not os.path.exists(p1):
             os.makedirs(os.path.join(p1, 'sub.1', 'sub.2'))
         if not os.path.exists(os.path.join(p1, 'sub.1', 'sub.2', 'testfile')):
-            file(os.path.join(p1, 'sub.1', 'sub.2', 'testfile'), 'w').close()
+            open(os.path.join(p1, 'sub.1', 'sub.2', 'testfile'), 'w').close()
 
         self.dm.pushDir(p1, posixpath.join(dvpath, 'push1'))
 
diff --git a/testing/mozbase/mozdevice/tests/sut.py b/testing/mozbase/mozdevice/tests/sut.py
index 76a5ed3136..dd8f37ea80 100644
--- a/testing/mozbase/mozdevice/tests/sut.py
+++ b/testing/mozbase/mozdevice/tests/sut.py
@@ -10,7 +10,7 @@ import time
 from threading import Thread
 
 
-class MockAgent(object):
+class MockAgent:
 
     MAX_WAIT_TIME_SECONDS = 10
     SOCKET_TIMEOUT_SECONDS = 5
diff --git a/testing/mozbase/mozdevice/tests/sut_copytree.py b/testing/mozbase/mozdevice/tests/sut_copytree.py
index ec22828d07..75a15df0a7 100644
--- a/testing/mozbase/mozdevice/tests/sut_copytree.py
+++ b/testing/mozbase/mozdevice/tests/sut_copytree.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 # 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,
diff --git a/testing/mozbase/mozdevice/tests/sut_fileMethods.py b/testing/mozbase/mozdevice/tests/sut_fileMethods.py
index 142950a816..7ec69302f4 100644
--- a/testing/mozbase/mozdevice/tests/sut_fileMethods.py
+++ b/testing/mozbase/mozdevice/tests/sut_fileMethods.py
@@ -40,7 +40,7 @@ class TestFileMethods(unittest.TestCase):
     def test_getFile(self):
 
         fname = "/mnt/sdcard/file"
-        commands = [("pull %s" % fname, "%s,%s\n%s" % (fname, len(self.content), self.content)),
+        commands = [("pull %s" % fname, "{},{}\n{}".format(fname, len(self.content), self.content)),
                     ("hash %s" % fname, self.temp_hash)]
 
         with tempfile.NamedTemporaryFile() as f:
@@ -57,7 +57,7 @@ class TestFileMethods(unittest.TestCase):
                     ("cd /mnt/sdcard", ""),
                     ("ls", "file"),
                     ("isdir %s" % fname, "FALSE"),
-                    ("pull %s" % fname, "%s,%s\n%s" % (fname, len(self.content), self.content)),
+                    ("pull %s" % fname, "{},{}\n{}".format(fname, len(self.content), self.content)),
                     ("hash %s" % fname, self.temp_hash)]
 
         tmpdir = tempfile.mkdtemp()
diff --git a/testing/mozbase/mozdevice/tests/sut_info.py b/testing/mozbase/mozdevice/tests/sut_info.py
index 93f3d42581..565dd3dc8a 100644
--- a/testing/mozbase/mozdevice/tests/sut_info.py
+++ b/testing/mozbase/mozdevice/tests/sut_info.py
@@ -40,7 +40,7 @@ class TestGetInfo(unittest.TestCase):
 
             expected = re.sub(r'\ +', ' ', self.commands[directive][1]).split('\n')
             # Account for slightly different return format for 'process'
-            if directive is 'process':
+            if directive == 'process':
                 expected = [[x] for x in expected]
 
             self.assertEqual(d.getInfo(directive=directive)[directive], expected)
diff --git a/testing/mozbase/mozdevice/tests/sut_movetree.py b/testing/mozbase/mozdevice/tests/sut_movetree.py
index 0e106577c8..a674391586 100644
--- a/testing/mozbase/mozdevice/tests/sut_movetree.py
+++ b/testing/mozbase/mozdevice/tests/sut_movetree.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 # 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,
diff --git a/testing/mozbase/mozdevice/tests/sut_pull.py b/testing/mozbase/mozdevice/tests/sut_pull.py
index c9fcae42a6..8fd12f9fb5 100644
--- a/testing/mozbase/mozdevice/tests/sut_pull.py
+++ b/testing/mozbase/mozdevice/tests/sut_pull.py
@@ -15,7 +15,7 @@ class PullTest(unittest.TestCase):
             # pull file is kind of gross, make sure we can still execute commands after it's done
             remoteName = "/mnt/sdcard/cheeseburgers"
             a = MockAgent(self, commands=[("pull %s" % remoteName,
-                                           "%s,%s\n%s" % (remoteName,
+                                           "{},{}\n{}".format(remoteName,
                                                           len(cheeseburgers),
                                                           cheeseburgers)),
                                           ("isdir /mnt/sdcard", "TRUE")])
@@ -32,7 +32,7 @@ class PullTest(unittest.TestCase):
         # to be larger file
         remoteName = "/mnt/sdcard/cheeseburgers"
         a = MockAgent(self, commands=[("pull %s" % remoteName,
-                                       "%s,15\n%s" % (remoteName,
+                                       "{},15\n{}".format(remoteName,
                                                       "cheeseburgh"))])
         d = mozdevice.DroidSUT("127.0.0.1", port=a.port,
                                logLevel=logging.DEBUG)
diff --git a/testing/mozbase/mozdevice/tests/sut_push.py b/testing/mozbase/mozdevice/tests/sut_push.py
index 023d5315cc..c906c9632d 100644
--- a/testing/mozbase/mozdevice/tests/sut_push.py
+++ b/testing/mozbase/mozdevice/tests/sut_push.py
@@ -18,7 +18,7 @@ class PushTest(unittest.TestCase):
 
         # (good response, no exception), (bad response, exception)
         for response in [(expectedResponse, False), ("BADHASH", True)]:
-            cmd = "push /mnt/sdcard/foobar %s\r\n%s" % (len(pushfile), pushfile)
+            cmd = "push /mnt/sdcard/foobar {}\r\n{}".format(len(pushfile), pushfile)
             a = MockAgent(self, commands=[("isdir /mnt/sdcard", "TRUE"),
                                           (cmd, response[0])])
             exceptionThrown = False
diff --git a/testing/mozbase/mozfile/mozfile/__init__.py b/testing/mozbase/mozfile/mozfile/__init__.py
index a527f0ad6d..011371a64b 100644
--- a/testing/mozbase/mozfile/mozfile/__init__.py
+++ b/testing/mozbase/mozfile/mozfile/__init__.py
@@ -3,6 +3,5 @@
 # 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
 
 from .mozfile import *
diff --git a/testing/mozbase/mozfile/mozfile/mozfile.py b/testing/mozbase/mozfile/mozfile/mozfile.py
index 94805594ec..d9ed7b828b 100644
--- a/testing/mozbase/mozfile/mozfile/mozfile.py
+++ b/testing/mozbase/mozfile/mozfile/mozfile.py
@@ -1,13 +1,11 @@
-# -*- coding: utf-8 -*-
-
 # 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/.
 
 # We don't import all modules at the top for performance reasons. See Bug 1008943
 
-from __future__ import absolute_import
 
+from __future__ import print_function
 from contextlib import contextmanager
 import errno
 import os
@@ -55,7 +53,7 @@ def extract_zip(src, dest):
         try:
             bundle = zipfile.ZipFile(src)
         except Exception:
-            print "src: %s" % src
+            print("src: %s" % src)
             raise
 
     namelist = bundle.namelist()
@@ -161,8 +159,8 @@ def _call_windows_retry(func, args=(), retry_max=5, retry_delay=0.5):
 
             retry_count += 1
 
-            print '%s() failed for "%s". Reason: %s (%s). Retrying...' % \
-                (func.__name__, args, e.strerror, e.errno)
+            print('%s() failed for "%s". Reason: %s (%s). Retrying...' % \
+                (func.__name__, args, e.strerror, e.errno))
             time.sleep(retry_count * retry_delay)
         else:
             # If no exception has been thrown it should be done
@@ -420,9 +418,9 @@ def is_url(thing):
     Return True if thing looks like a URL.
     """
 
-    import urlparse
+    import urllib.parse
 
-    parsed = urlparse.urlparse(thing)
+    parsed = urllib.parse.urlparse(thing)
     if 'scheme' in parsed:
         return len(parsed.scheme) >= 2
     else:
@@ -436,7 +434,7 @@ def load(resource):
     result of urllib2.urlopen()
     """
 
-    import urllib2
+    import urllib.request, urllib.error, urllib.parse
 
     # handle file URLs separately due to python stdlib limitations
     if resource.startswith('file://'):
@@ -444,6 +442,6 @@ def load(resource):
 
     if not is_url(resource):
         # if no scheme is given, it is a file path
-        return file(resource)
+        return open(resource)
 
-    return urllib2.urlopen(resource)
+    return six.moves.urllib.request.urlopen(resource)
diff --git a/testing/mozbase/mozfile/tests/stubs.py b/testing/mozbase/mozfile/tests/stubs.py
index 06d79e7af1..6d7e2ec263 100644
--- a/testing/mozbase/mozfile/tests/stubs.py
+++ b/testing/mozbase/mozfile/tests/stubs.py
@@ -25,7 +25,7 @@ def create_stub():
             if not os.path.exists(dirname):
                 os.makedirs(dirname)
             contents = path[-1]
-            f = file(fullpath, 'w')
+            f = open(fullpath, 'w')
             f.write(contents)
             f.close()
         return tempdir
diff --git a/testing/mozbase/mozfile/tests/test_extract.py b/testing/mozbase/mozfile/tests/test_extract.py
index e91f52349b..71a53b8cb3 100644
--- a/testing/mozbase/mozfile/tests/test_extract.py
+++ b/testing/mozbase/mozfile/tests/test_extract.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 
+from __future__ import print_function
 import os
 import shutil
 import tarfile
@@ -21,10 +22,10 @@ class TestExtract(unittest.TestCase):
             path = os.path.join(directory, *f)
             exists = os.path.exists(path)
             if not exists:
-                print "%s does not exist" % (os.path.join(f))
+                print("%s does not exist" % (os.path.join(f)))
             self.assertTrue(exists)
             if exists:
-                contents = file(path).read().strip()
+                contents = open(path).read().strip()
                 self.assertTrue(contents == f[-1])
 
     def test_extract_zipfile(self):
diff --git a/testing/mozbase/mozfile/tests/test_load.py b/testing/mozbase/mozfile/tests/test_load.py
index 13a5b519c1..f6630fc6ec 100755
--- a/testing/mozbase/mozfile/tests/test_load.py
+++ b/testing/mozbase/mozfile/tests/test_load.py
@@ -45,7 +45,7 @@ class TestLoad(unittest.TestCase):
             tmp.close()
 
             # read the file
-            contents = file(tmp.name).read()
+            contents = open(tmp.name).read()
             self.assertEqual(contents, 'foo bar')
 
             # read the file with load and a file path
diff --git a/testing/mozbase/mozfile/tests/test_move_remove.py b/testing/mozbase/mozfile/tests/test_move_remove.py
index e9d0cd4347..72cd444a33 100644
--- a/testing/mozbase/mozfile/tests/test_move_remove.py
+++ b/testing/mozbase/mozfile/tests/test_move_remove.py
@@ -77,7 +77,7 @@ class MozfileRemoveTestCase(unittest.TestCase):
         """Test removing a directory with an open file"""
         # Open a file in the generated stub
         filepath = os.path.join(self.tempdir, *stubs.files[1])
-        f = file(filepath, 'w')
+        f = open(filepath, 'w')
         f.write('foo-bar')
 
         # keep file open and then try removing the dir-tree
diff --git a/testing/mozbase/mozfile/tests/test_tempfile.py b/testing/mozbase/mozfile/tests/test_tempfile.py
index 3c3d26d5d6..c395e484ac 100644
--- a/testing/mozbase/mozfile/tests/test_tempfile.py
+++ b/testing/mozbase/mozfile/tests/test_tempfile.py
@@ -66,7 +66,7 @@ class TestNamedTemporaryFile(unittest.TestCase):
         path = None
         with mozfile.NamedTemporaryFile(delete=True) as tf:
             path = tf.name
-        self.assertTrue(isinstance(path, basestring))
+        self.assertTrue(isinstance(path, str))
         self.assertFalse(os.path.exists(path))
 
         # it is also deleted when __del__ is called
diff --git a/testing/mozbase/mozhttpd/mozhttpd/__init__.py b/testing/mozbase/mozhttpd/mozhttpd/__init__.py
index c15b0d0285..1575bd59f2 100644
--- a/testing/mozbase/mozhttpd/mozhttpd/__init__.py
+++ b/testing/mozbase/mozhttpd/mozhttpd/__init__.py
@@ -37,12 +37,12 @@ content from the current directory, defines a single API endpoint
                             urlhandlers = [ { 'method': 'GET',
                                               'path': '/api/resources/([^/]+)/?',
                                               'function': resource_get } ])
-  print "Serving '%s' at %s:%s" % (httpd.docroot, httpd.host, httpd.port)
+  print("Serving '%s' at %s:%s" % (httpd.docroot, httpd.host, httpd.port))
   httpd.start(block=True)
 
 """
 
-from mozhttpd import MozHttpd, Request, RequestHandler, main
-from handlers import json_response
+from .mozhttpd import MozHttpd, Request, RequestHandler, main
+from .handlers import json_response
 
 __all__ = ['MozHttpd', 'Request', 'RequestHandler', 'main', 'json_response']
diff --git a/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py b/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
index 4ca0847d2a..dfd2a6a435 100755
--- a/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
+++ b/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
@@ -4,8 +4,9 @@
 # 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/.
 
-import BaseHTTPServer
-import SimpleHTTPServer
+from __future__ import print_function
+import http.server as BaseHTTPServer
+import http.server as SimpleHTTPServer
 import errno
 import logging
 import threading
@@ -13,12 +14,13 @@ import posixpath
 import socket
 import sys
 import os
-import urllib
-import urlparse
+import urllib.request
+import urllib.parse
+import urllib.error
 import re
 import moznetwork
 import time
-from SocketServer import ThreadingMixIn
+from socketserver import ThreadingMixIn
 
 
 class EasyServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
@@ -26,7 +28,7 @@ class EasyServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
     acceptable_errors = (errno.EPIPE, errno.ECONNABORTED)
 
     def handle_error(self, request, client_address):
-        error = sys.exc_value
+        error = sys.exc_info()[1]
 
         if ((isinstance(error, socket.error) and
              isinstance(error.args, tuple) and
@@ -48,7 +50,7 @@ class Request(object):
     def __init__(self, uri, headers, rfile=None):
         self.uri = uri
         self.headers = headers
-        parsed = urlparse.urlsplit(uri)
+        parsed = urllib.parse.urlsplit(uri)
         for i, attr in enumerate(self.uri_attrs):
             setattr(self, attr, parsed[i])
         try:
@@ -87,7 +89,7 @@ class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
                 (response_code, headerdict, data) = \
                     handler['function'](self.request, *m.groups())
                 self.send_response(response_code)
-                for (keyword, value) in headerdict.iteritems():
+                for (keyword, value) in headerdict.items():
                     self.send_header(keyword, value)
                 self.end_headers()
                 self.wfile.write(data)
@@ -100,9 +102,9 @@ class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
         """Find the on-disk path to serve this request from,
         using self.path_mappings and self.docroot.
         Return (url_path, disk_path)."""
-        path_components = filter(None, self.request.path.split('/'))
-        for prefix, disk_path in self.path_mappings.iteritems():
-            prefix_components = filter(None, prefix.split('/'))
+        path_components = [_f for _f in self.request.path.split('/') if _f]
+        for prefix, disk_path in self.path_mappings.items():
+            prefix_components = [_f for _f in prefix.split('/') if _f]
             if len(path_components) < len(prefix_components):
                 continue
             if path_components[:len(prefix_components)] == prefix_components:
@@ -156,9 +158,9 @@ class RequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
         # except we serve from self.docroot instead of os.getcwd(), and
         # parse_request()/do_GET() have already stripped the query string and
         # fragment and mangled the path for proxying, if required.
-        path = posixpath.normpath(urllib.unquote(self.path))
+        path = posixpath.normpath(urllib.parse.unquote(self.path))
         words = path.split('/')
-        words = filter(None, words)
+        words = [_f for _f in words if _f]
         path = self.disk_root
         for word in words:
             drive, word = os.path.splitdrive(word)
@@ -323,7 +325,7 @@ def main(args=sys.argv[1:]):
     # create the server
     server = MozHttpd(host=host, port=options.port, docroot=options.docroot)
 
-    print "Serving '%s' at %s:%s" % (server.docroot, server.host, server.port)
+    print(("Serving '%s' at %s:%s" % (server.docroot, server.host, server.port)))
     server.start(block=True)
 
 if __name__ == '__main__':
diff --git a/testing/mozbase/mozhttpd/tests/api.py b/testing/mozbase/mozhttpd/tests/api.py
index b785ac5ef7..82a03a46b5 100644
--- a/testing/mozbase/mozhttpd/tests/api.py
+++ b/testing/mozbase/mozhttpd/tests/api.py
@@ -6,7 +6,7 @@
 
 import mozfile
 import mozhttpd
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import os
 import unittest
 import json
@@ -42,7 +42,7 @@ class ApiTest(unittest.TestCase):
                       'query': request.query})
 
     def get_url(self, path, server_port, querystr):
-        url = "http://127.0.0.1:%s%s" % (server_port, path)
+        url = "http://127.0.0.1:{}{}".format(server_port, path)
         if querystr:
             url += "?%s" % querystr
         return url
@@ -50,7 +50,7 @@ class ApiTest(unittest.TestCase):
     def try_get(self, server_port, querystr):
         self.resource_get_called = 0
 
-        f = urllib2.urlopen(self.get_url('/api/resource/1', server_port, querystr))
+        f = six.moves.urllib.request.urlopen(self.get_url('/api/resource/1', server_port, querystr))
         try:
             self.assertEqual(f.getcode(), 200)
         except AttributeError:
@@ -63,9 +63,9 @@ class ApiTest(unittest.TestCase):
 
         postdata = {'hamburgers': '1234'}
         try:
-            f = urllib2.urlopen(self.get_url('/api/resource/', server_port, querystr),
+            f = six.moves.urllib.request.urlopen(self.get_url('/api/resource/', server_port, querystr),
                                 data=json.dumps(postdata))
-        except urllib2.HTTPError as e:
+        except six.moves.urllib.error.HTTPError as e:
             # python 2.4
             self.assertEqual(e.code, 201)
             body = e.fp.read()
@@ -80,8 +80,8 @@ class ApiTest(unittest.TestCase):
     def try_del(self, server_port, querystr):
         self.resource_del_called = 0
 
-        opener = urllib2.build_opener(urllib2.HTTPHandler)
-        request = urllib2.Request(self.get_url('/api/resource/1', server_port, querystr))
+        opener = six.moves.urllib.request.build_opener(six.moves.urllib.request.HTTPHandler)
+        request = six.moves.urllib.request.Request(self.get_url('/api/resource/1', server_port, querystr))
         request.get_method = lambda: 'DEL'
         f = opener.open(request)
 
@@ -123,8 +123,8 @@ class ApiTest(unittest.TestCase):
         # GET: By default we don't serve any files if we just define an API
         exception_thrown = False
         try:
-            urllib2.urlopen(self.get_url('/', server_port, None))
-        except urllib2.HTTPError as e:
+            six.moves.urllib.request.urlopen(self.get_url('/', server_port, None))
+        except six.moves.urllib.error.HTTPError as e:
             self.assertEqual(e.code, 404)
             exception_thrown = True
         self.assertTrue(exception_thrown)
@@ -139,8 +139,8 @@ class ApiTest(unittest.TestCase):
         # GET: Return 404 for non-existent endpoint
         exception_thrown = False
         try:
-            urllib2.urlopen(self.get_url('/api/resource/', server_port, None))
-        except urllib2.HTTPError as e:
+            six.moves.urllib.request.urlopen(self.get_url('/api/resource/', server_port, None))
+        except six.moves.urllib.error.HTTPError as e:
             self.assertEqual(e.code, 404)
             exception_thrown = True
         self.assertTrue(exception_thrown)
@@ -148,9 +148,9 @@ class ApiTest(unittest.TestCase):
         # POST: POST should also return 404
         exception_thrown = False
         try:
-            urllib2.urlopen(self.get_url('/api/resource/', server_port, None),
+            six.moves.urllib.request.urlopen(self.get_url('/api/resource/', server_port, None),
                             data=json.dumps({}))
-        except urllib2.HTTPError as e:
+        except six.moves.urllib.error.HTTPError as e:
             self.assertEqual(e.code, 404)
             exception_thrown = True
         self.assertTrue(exception_thrown)
@@ -158,12 +158,12 @@ class ApiTest(unittest.TestCase):
         # DEL: DEL should also return 404
         exception_thrown = False
         try:
-            opener = urllib2.build_opener(urllib2.HTTPHandler)
-            request = urllib2.Request(self.get_url('/api/resource/', server_port,
+            opener = six.moves.urllib.request.build_opener(six.moves.urllib.request.HTTPHandler)
+            request = six.moves.urllib.request.Request(self.get_url('/api/resource/', server_port,
                                                    None))
             request.get_method = lambda: 'DEL'
             opener.open(request)
-        except urllib2.HTTPError:
+        except six.moves.urllib.error.HTTPError:
             self.assertEqual(e.code, 404)
             exception_thrown = True
         self.assertTrue(exception_thrown)
@@ -177,7 +177,7 @@ class ApiTest(unittest.TestCase):
         server_port = httpd.httpd.server_port
 
         # We defined a docroot, so we expect a directory listing
-        f = urllib2.urlopen(self.get_url('/', server_port, None))
+        f = six.moves.urllib.request.urlopen(self.get_url('/', server_port, None))
         try:
             self.assertEqual(f.getcode(), 200)
         except AttributeError:
@@ -193,7 +193,7 @@ class ProxyTest(unittest.TestCase):
 
     def tearDown(self):
         # reset proxy opener in case it changed
-        urllib2.install_opener(None)
+        six.moves.urllib.request.install_opener(None)
 
     def test_proxy(self):
         docroot = tempfile.mkdtemp()
@@ -207,7 +207,7 @@ class ProxyTest(unittest.TestCase):
 
         def index_contents(host): return '%s index' % host
 
-        index = file(os.path.join(docroot, index_filename), 'w')
+        index = open(os.path.join(docroot, index_filename), 'w')
         index.write(index_contents('*'))
         index.close()
 
@@ -215,12 +215,12 @@ class ProxyTest(unittest.TestCase):
         httpd.start(block=False)
         server_port = httpd.httpd.server_port
 
-        proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
+        proxy_support = six.moves.urllib.request.ProxyHandler({'http': 'http://127.0.0.1:%d' %
                                               server_port})
-        urllib2.install_opener(urllib2.build_opener(proxy_support))
+        six.moves.urllib.request.install_opener(six.moves.urllib.request.build_opener(proxy_support))
 
         for host in hosts:
-            f = urllib2.urlopen(url(host))
+            f = six.moves.urllib.request.urlopen(url(host))
             try:
                 self.assertEqual(f.getcode(), 200)
             except AttributeError:
@@ -235,18 +235,18 @@ class ProxyTest(unittest.TestCase):
         httpd.start(block=False)
         server_port = httpd.httpd.server_port
 
-        proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
+        proxy_support = six.moves.urllib.request.ProxyHandler({'http': 'http://127.0.0.1:%d' %
                                               server_port})
-        urllib2.install_opener(urllib2.build_opener(proxy_support))
+        six.moves.urllib.request.install_opener(six.moves.urllib.request.build_opener(proxy_support))
 
         # set up dirs
         for host in hosts:
             os.mkdir(os.path.join(docroot, host))
-            file(os.path.join(docroot, host, index_filename), 'w') \
+            open(os.path.join(docroot, host, index_filename), 'w') \
                 .write(index_contents(host))
 
         for host in hosts:
-            f = urllib2.urlopen(url(host))
+            f = six.moves.urllib.request.urlopen(url(host))
             try:
                 self.assertEqual(f.getcode(), 200)
             except AttributeError:
@@ -255,8 +255,8 @@ class ProxyTest(unittest.TestCase):
 
         exc = None
         try:
-            urllib2.urlopen(url(unproxied_host))
-        except urllib2.HTTPError as e:
+            six.moves.urllib.request.urlopen(url(unproxied_host))
+        except six.moves.urllib.error.HTTPError as e:
             exc = e
         self.assertNotEqual(exc, None)
         self.assertEqual(exc.code, 404)
diff --git a/testing/mozbase/mozhttpd/tests/filelisting.py b/testing/mozbase/mozhttpd/tests/filelisting.py
index 6abea757f2..75b59a70cf 100644
--- a/testing/mozbase/mozhttpd/tests/filelisting.py
+++ b/testing/mozbase/mozhttpd/tests/filelisting.py
@@ -5,7 +5,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import mozhttpd
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import os
 import unittest
 import re
@@ -20,9 +20,9 @@ class FileListingTest(unittest.TestCase):
 
         httpd = mozhttpd.MozHttpd(port=0, docroot=here)
         httpd.start(block=False)
-        f = urllib2.urlopen("http://%s:%s/%s" % ('127.0.0.1', httpd.httpd.server_port, path))
+        f = six.moves.urllib.request.urlopen("http://{}:{}/{}".format('127.0.0.1', httpd.httpd.server_port, path))
         for line in f.readlines():
-            webline = re.sub('\<[a-zA-Z0-9\-\_\.\=\"\'\/\\\%\!\@\#\$\^\&\*\(\) ]*\>',
+            webline = re.sub('\\<[a-zA-Z0-9\\-\\_\\.\\=\"\'\\/\\\\%\\!\\@\\#\\$\\^\\&\\*\\(\\) ]*\\>',
                              '', line.strip('\n')).strip('/').strip().strip('@')
 
             if webline and not webline.startswith("Directory listing for"):
diff --git a/testing/mozbase/mozhttpd/tests/paths.py b/testing/mozbase/mozhttpd/tests/paths.py
index 45ae40144d..e6bde9f3ee 100644
--- a/testing/mozbase/mozhttpd/tests/paths.py
+++ b/testing/mozbase/mozhttpd/tests/paths.py
@@ -7,19 +7,19 @@ from mozfile import TemporaryDirectory
 import mozhttpd
 import os
 import unittest
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
 
 class PathTest(unittest.TestCase):
 
     def try_get(self, url, expected_contents):
-        f = urllib2.urlopen(url)
+        f = six.moves.urllib.request.urlopen(url)
         self.assertEqual(f.getcode(), 200)
         self.assertEqual(f.read(), expected_contents)
 
     def try_get_expect_404(self, url):
-        with self.assertRaises(urllib2.HTTPError) as cm:
-            urllib2.urlopen(url)
+        with self.assertRaises(six.moves.urllib.error.HTTPError) as cm:
+            six.moves.urllib.request.urlopen(url)
         self.assertEqual(404, cm.exception.code)
 
     def test_basic(self):
diff --git a/testing/mozbase/mozhttpd/tests/requestlog.py b/testing/mozbase/mozhttpd/tests/requestlog.py
index bf2c59ec3f..2ee0772113 100644
--- a/testing/mozbase/mozhttpd/tests/requestlog.py
+++ b/testing/mozbase/mozhttpd/tests/requestlog.py
@@ -3,7 +3,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import mozhttpd
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import os
 import unittest
 
@@ -16,8 +16,8 @@ class RequestLogTest(unittest.TestCase):
 
         httpd = mozhttpd.MozHttpd(port=0, docroot=here, log_requests=log_requests)
         httpd.start(block=False)
-        url = "http://%s:%s/" % ('127.0.0.1', httpd.httpd.server_port)
-        f = urllib2.urlopen(url)
+        url = "http://{}:{}/".format('127.0.0.1', httpd.httpd.server_port)
+        f = six.moves.urllib.request.urlopen(url)
         f.read()
 
         return httpd.request_log
diff --git a/testing/mozbase/mozinfo/mozinfo/__init__.py b/testing/mozbase/mozinfo/mozinfo/__init__.py
index 7d0483cb57..d02f9510e1 100644
--- a/testing/mozbase/mozinfo/mozinfo/__init__.py
+++ b/testing/mozbase/mozinfo/mozinfo/__init__.py
@@ -3,7 +3,6 @@
 # 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
 
 """
 interface to transform introspected system information to a format palatable to
diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
index 81a30307dd..bd767de198 100755
--- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py
+++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
@@ -8,7 +8,6 @@
 # linux) to the information; I certainly wouldn't want anyone parsing this
 # information and having behaviour depend on it
 
-from __future__ import absolute_import
 
 import os
 import platform
@@ -92,10 +91,16 @@ elif system.startswith('MINGW'):
     info['os'] = 'win'
     os_version = version = unknown
 elif system == "Linux":
-    if hasattr(platform, "linux_distribution"):
-        (distro, os_version, codename) = platform.linux_distribution()
-    else:
-        (distro, os_version, codename) = platform.dist()
+    try:
+        import distro as _distro_module
+        distro = _distro_module.name()
+        os_version = _distro_module.version()
+        codename = _distro_module.codename()
+    except ImportError:
+        if hasattr(platform, "linux_distribution"):
+            (distro, os_version, codename) = platform.linux_distribution()
+        else:
+            distro, os_version, codename = '', '', ''
     if not processor:
         processor = machine
     version = "%s %s" % (distro, os_version)
@@ -140,7 +145,7 @@ elif processor.upper() == "AMD64":
     processor = "x86_64"
 elif processor == "Power Macintosh":
     processor = "ppc"
-bits = re.search('(\d+)bit', bits).group(1)
+bits = re.search(r'(\d+)bit', bits).group(1)
 info.update({'processor': processor,
              'bits': int(bits),
              })
@@ -184,7 +189,7 @@ def update(new_info):
                      to a json file containing the new info.
     """
 
-    if isinstance(new_info, basestring):
+    if isinstance(new_info, str):
         # lazy import
         import mozfile
         import json
@@ -246,7 +251,7 @@ def output_to_file(path):
 update({})
 
 # exports
-__all__ = info.keys()
+__all__ = list(info.keys())
 __all__ += ['is' + os_name.title() for os_name in choices['os']]
 __all__ += [
     'info',
@@ -286,15 +291,15 @@ def main(args=None):
     flag = False
     for key, value in options.__dict__.items():
         if value is True:
-            print '%s choices: %s' % (key, ' '.join([str(choice)
-                                                     for choice in choices[key]]))
+            print('%s choices: %s' % (key, ' '.join([str(choice)
+                                                     for choice in choices[key]])))
             flag = True
     if flag:
         return
 
     # otherwise, print out all info
     for key, value in info.items():
-        print '%s: %s' % (key, value)
+        print('%s: %s' % (key, value))
 
 if __name__ == '__main__':
     main()
diff --git a/testing/mozbase/mozinfo/mozinfo/string_version.py b/testing/mozbase/mozinfo/mozinfo/string_version.py
index fd77fa566a..a554677cd4 100644
--- a/testing/mozbase/mozinfo/mozinfo/string_version.py
+++ b/testing/mozbase/mozinfo/mozinfo/string_version.py
@@ -2,16 +2,40 @@
 # 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 distutils.version import LooseVersion
-
-
+try:
+    from distutils.version import LooseVersion
+except ImportError:
+    import re as _re
+    class LooseVersion:
+        def __init__(self, vstring):
+            self.vstring = vstring
+            self.version = [int(x) if x.isdigit() else x for x in _re.split(r'[.\-]', vstring)]
+        def __str__(self): return self.vstring
+        def __repr__(self): return "LooseVersion ('%s')" % str(self)
+        def _cmp(self, other):
+            if not isinstance(other, LooseVersion): other = LooseVersion(other)
+            a, b = self.version, other.version
+            for i in range(max(len(a), len(b))):
+                va = a[i] if i < len(a) else 0
+                vb = b[i] if i < len(b) else 0
+                if type(va) != type(vb): va, vb = str(va), str(vb)
+                if va < vb: return -1
+                if va > vb: return 1
+            return 0
+        def __eq__(self, other): return self._cmp(other) == 0
+        def __lt__(self, other): return self._cmp(other) < 0
+        def __le__(self, other): return self._cmp(other) <= 0
+        def __gt__(self, other): return self._cmp(other) > 0
+        def __ge__(self, other): return self._cmp(other) >= 0
 class StringVersion(str):
     """
     A string version that can be compared with comparison operators.
     """
 
+    def __new__(cls, vstring):
+        return str.__new__(cls, vstring)
+
     def __init__(self, vstring):
-        str.__init__(self, vstring)
         self.version = LooseVersion(vstring)
 
     def __repr__(self):
diff --git a/testing/mozbase/mozinfo/tests/test.py b/testing/mozbase/mozinfo/tests/test.py
index b9457cff9d..af4662c460 100644
--- a/testing/mozbase/mozinfo/tests/test.py
+++ b/testing/mozbase/mozinfo/tests/test.py
@@ -5,7 +5,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import json
-import mock
+from unittest import mock
 import os
 import shutil
 import sys
diff --git a/testing/mozbase/mozinstall/mozinstall/__init__.py b/testing/mozbase/mozinstall/mozinstall/__init__.py
index 5f96b7facd..09c6d10a3d 100644
--- a/testing/mozbase/mozinstall/mozinstall/__init__.py
+++ b/testing/mozbase/mozinstall/mozinstall/__init__.py
@@ -3,4 +3,4 @@
 # 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 mozinstall import *
+from .mozinstall import *
diff --git a/testing/mozbase/mozinstall/mozinstall/mozinstall.py b/testing/mozbase/mozinstall/mozinstall/mozinstall.py
index b4c6f95f74..69aead088f 100755
--- a/testing/mozbase/mozinstall/mozinstall/mozinstall.py
+++ b/testing/mozbase/mozinstall/mozinstall/mozinstall.py
@@ -2,6 +2,7 @@
 # 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 print_function
 from optparse import OptionParser
 import os
 import shutil
@@ -13,6 +14,7 @@ import zipfile
 
 import mozfile
 import mozinfo
+import six
 
 try:
     import pefile
@@ -134,9 +136,9 @@ def install(src, dest):
                     pass
         if issubclass(cls, Exception):
             error = InstallError('Failed to install "%s (%s)"' % (src, str(exc)))
-            raise InstallError, error, trbk
+            six.reraise(InstallError, error, trbk)
         # any other kind of exception like KeyboardInterrupt is just re-raised.
-        raise cls, exc, trbk
+        six.reraise(cls, exc, trbk)
 
     finally:
         # trbk won't get GC'ed due to circular reference
@@ -207,7 +209,7 @@ def uninstall(install_folder):
         if os.path.isfile(log_file):
             trbk = None
             try:
-                cmdArgs = ['%s\uninstall\helper.exe' % install_folder, '/S']
+                cmdArgs = ['%s\uninstall\\helper.exe' % install_folder, '/S']
                 result = subprocess.call(cmdArgs)
                 if result is not 0:
                     raise Exception('Execution of uninstaller failed.')
@@ -222,10 +224,10 @@ def uninstall(install_folder):
                     if time.time() > end_time:
                         raise Exception('Failure removing uninstall folder.')
 
-            except Exception, ex:
+            except Exception as ex:
                 cls, exc, trbk = sys.exc_info()
                 error = UninstallError('Failed to uninstall %s (%s)' % (install_folder, str(ex)))
-                raise UninstallError, error, trbk
+                six.reraise(UninstallError, error, trbk)
 
             finally:
                 # trbk won't get GC'ed due to circular reference
@@ -328,7 +330,7 @@ def install_cli(argv=sys.argv[1:]):
         install_path = install(src, options.dest)
         binary = get_binary(install_path, app_name=options.app)
 
-    print binary
+    print(binary)
 
 
 def uninstall_cli(argv=sys.argv[1:]):
diff --git a/testing/mozbase/mozinstall/setup.py b/testing/mozbase/mozinstall/setup.py
index 7759f0728e..8d5320183e 100644
--- a/testing/mozbase/mozinstall/setup.py
+++ b/testing/mozbase/mozinstall/setup.py
@@ -7,8 +7,8 @@ from setuptools import setup
 
 try:
     here = os.path.dirname(os.path.abspath(__file__))
-    description = file(os.path.join(here, 'README.md')).read()
-except IOError:
+    description = open(os.path.join(here, 'README.md')).read()
+except OSError:
     description = None
 
 PACKAGE_VERSION = '1.12'
diff --git a/testing/mozbase/mozleak/mozleak/leaklog.py b/testing/mozbase/mozleak/mozleak/leaklog.py
index 9688974d1c..ba1980d530 100644
--- a/testing/mozbase/mozleak/mozleak/leaklog.py
+++ b/testing/mozbase/mozleak/mozleak/leaklog.py
@@ -41,7 +41,7 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
     leakedObjectAnalysis = []
     leakedObjectNames = []
     recordLeakedObjects = False
-    with open(leakLogFileName, "r") as leaks:
+    with open(leakLogFileName) as leaks:
         for line in leaks:
             if line.find("purposefully crash") > -1:
                 crashedOnPurpose = True
diff --git a/testing/mozbase/mozlog/mozlog/commandline.py b/testing/mozbase/mozlog/mozlog/commandline.py
index 1077081548..d12d60aabb 100644
--- a/testing/mozbase/mozlog/mozlog/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/commandline.py
@@ -121,7 +121,7 @@ def add_logging_group(parser, include_formatters=None):
                          "or '-' to write to stdout.")
 
     if include_formatters is None:
-        include_formatters = log_formatters.keys()
+        include_formatters = list(log_formatters.keys())
 
     if isinstance(parser, optparse.OptionParser):
         group = optparse.OptionGroup(parser,
@@ -136,16 +136,16 @@ def add_logging_group(parser, include_formatters=None):
         opt_log_type = log_file
         group_add = group.add_argument
 
-    for name, (cls, help_str) in log_formatters.iteritems():
+    for name, (cls, help_str) in log_formatters.items():
         if name in include_formatters:
             group_add("--log-" + name, action="append", type=opt_log_type,
                       help=help_str)
 
-    for optname, (cls, help_str, formatters_, action) in fmt_options.iteritems():
+    for optname, (cls, help_str, formatters_, action) in fmt_options.items():
         for fmt in formatters_:
             # make sure fmt is in log_formatters and is accepted
             if fmt in log_formatters and fmt in include_formatters:
-                group_add("--log-%s-%s" % (fmt, optname), action=action,
+                group_add("--log-{}-{}".format(fmt, optname), action=action,
                           help=help_str, default=None)
 
 
@@ -165,12 +165,12 @@ def setup_handlers(logger, formatters, formatter_options, allow_unused_options=F
                list(unused_options))
         raise ValueError(msg)
 
-    for fmt, streams in formatters.iteritems():
+    for fmt, streams in formatters.items():
         formatter_cls = log_formatters[fmt][0]
         formatter = formatter_cls()
         handler_wrappers_and_options = []
 
-        for option, value in formatter_options[fmt].iteritems():
+        for option, value in formatter_options[fmt].items():
             wrapper, wrapper_args = None, ()
             if option == "valgrind":
                 wrapper = valgrind_handler_wrapper
@@ -232,7 +232,7 @@ def setup_logging(logger, args, defaults=None, formatter_defaults=None,
         else:
             defaults = {"raw": sys.stdout}
 
-    for name, values in args.iteritems():
+    for name, values in args.items():
         parts = name.split('_')
         if len(parts) > 3:
             continue
@@ -246,7 +246,7 @@ def setup_logging(logger, args, defaults=None, formatter_defaults=None,
                 _, formatter = parts
                 for value in values:
                     found = True
-                    if isinstance(value, basestring):
+                    if isinstance(value, str):
                         value = log_file(value)
                     if value == sys.stdout:
                         found_stdout_logger = True
@@ -260,11 +260,11 @@ def setup_logging(logger, args, defaults=None, formatter_defaults=None,
 
     # If there is no user-specified logging, go with the default options
     if not found:
-        for name, value in defaults.iteritems():
+        for name, value in defaults.items():
             formatters[name].append(value)
 
-    elif not found_stdout_logger and sys.stdout in defaults.values():
-        for name, value in defaults.iteritems():
+    elif not found_stdout_logger and sys.stdout in list(defaults.values()):
+        for name, value in defaults.items():
             if value == sys.stdout:
                 formatters[name].append(value)
 
diff --git a/testing/mozbase/mozlog/mozlog/formatters/__init__.py b/testing/mozbase/mozlog/mozlog/formatters/__init__.py
index 5d37ecda81..0ab088a5a8 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/__init__.py
@@ -2,12 +2,12 @@
 # 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 unittest import UnittestFormatter
-from xunit import XUnitFormatter
-from html import HTMLFormatter
-from machformatter import MachFormatter
-from tbplformatter import TbplFormatter
-from errorsummary import ErrorSummaryFormatter
+from .unittest import UnittestFormatter
+from .xunit import XUnitFormatter
+from .html import HTMLFormatter
+from .machformatter import MachFormatter
+from .tbplformatter import TbplFormatter
+from .errorsummary import ErrorSummaryFormatter
 
 try:
     import ujson as json
diff --git a/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py b/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
index 5e0e844743..5040995fac 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
@@ -4,7 +4,7 @@
 
 import json
 
-from base import BaseFormatter
+from .base import BaseFormatter
 
 
 class ErrorSummaryFormatter(BaseFormatter):
diff --git a/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py b/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
index e607ecb87e..0926e46312 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
@@ -1,3 +1,3 @@
-from html import HTMLFormatter
+from .html import HTMLFormatter
 
 __all__ = ['HTMLFormatter']
diff --git a/testing/mozbase/mozlog/mozlog/formatters/html/html.py b/testing/mozbase/mozlog/mozlog/formatters/html/html.py
index 0ec244aa6a..c176f2672a 100755
--- a/testing/mozbase/mozlog/mozlog/formatters/html/html.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/html.py
@@ -4,7 +4,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import base64
-import cgi
+import html as _html_escape_module
 from datetime import datetime
 import os
 
@@ -158,7 +158,7 @@ class HTMLFormatter(base.BaseFormatter):
                     # Encode base64 to avoid that some browsers (such as Firefox, Opera)
                     # treats '#' as the start of another link if it is contained in the data URL.
                     # Use 'charset=utf-8' to show special characters like Chinese.
-                    utf_encoded = unicode(content).encode('utf-8', 'xmlcharrefreplace')
+                    utf_encoded = str(content).encode('utf-8', 'xmlcharrefreplace')
                     href = 'data:text/html;charset=utf-8;base64,%s' % base64.b64encode(utf_encoded)
 
                 links_html.append(html.a(
@@ -177,9 +177,9 @@ class HTMLFormatter(base.BaseFormatter):
                     log.append(line[:80])
                 else:
                     if line.lower().find("error") != -1 or line.lower().find("exception") != -1:
-                        log.append(html.span(raw(cgi.escape(line)), class_='error'))
+                        log.append(html.span(raw(_html_escape_module.escape(line)), class_='error'))
                     else:
-                        log.append(raw(cgi.escape(line)))
+                        log.append(raw(_html_escape_module.escape(line)))
                 log.append(html.br())
             additional_html.append(log)
 
@@ -198,7 +198,7 @@ class HTMLFormatter(base.BaseFormatter):
                 self.head,
                 html.body(
                     html.script(raw(main_f.read())),
-                    html.p('Report generated on %s at %s' % (
+                    html.p('Report generated on {} at {}'.format(
                         generated.strftime('%d-%b-%Y'),
                         generated.strftime('%H:%M:%S'))),
                     html.h2('Environment'),
@@ -208,7 +208,7 @@ class HTMLFormatter(base.BaseFormatter):
                         id='environment'),
 
                     html.h2('Summary'),
-                    html.p('%i tests ran in %.1f seconds.' % (sum(self.test_count.itervalues()),
+                    html.p('%i tests ran in %.1f seconds.' % (sum(self.test_count.values()),
                                                               (self.suite_times["end"] -
                                                                self.suite_times["start"]) / 1000.),
                            html.br(),
@@ -233,4 +233,4 @@ class HTMLFormatter(base.BaseFormatter):
                         html.tbody(self.result_rows,
                                    id='results-table-body')], id='results-table')))
 
-        return u"<!DOCTYPE html>\n" + doc.unicode(indent=2)
+        return "<!DOCTYPE html>\n" + doc.str(indent=2)
diff --git a/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py b/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
index e5998cda33..e405999c6b 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
@@ -24,18 +24,13 @@ by holger krekel, holger at merlinux eu. 2009
 import sys
 import re
 
-if sys.version_info >= (3, 0):
-    def u(s):
-        return s
+def u(s):
+    return s
 
-    def unicode(x):
-        if hasattr(x, '__unicode__'):
-            return x.__unicode__()
-        return str(x)
-else:
-    def u(s):
-        return unicode(s)
-    unicode = unicode
+def str(x):
+    if hasattr(x, '__unicode__'):
+        return x.__unicode__()
+    return str(x)
 
 
 class NamespaceMetaclass(type):
@@ -58,20 +53,20 @@ class NamespaceMetaclass(type):
 
 class Tag(list):
 
-    class Attr(object):
+    class Attr:
 
         def __init__(self, **kwargs):
             self.__dict__.update(kwargs)
 
     def __init__(self, *args, **kwargs):
-        super(Tag, self).__init__(args)
+        super().__init__(args)
         self.attr = self.Attr(**kwargs)
 
     def __unicode__(self):
-        return self.unicode(indent=0)
+        return self.str(indent=0)
     __str__ = __unicode__
 
-    def unicode(self, indent=2):
+    def str(self, indent=2):
         l = []
         SimpleUnicodeVisitor(l.append, indent).visit(self)
         return u("").join(l)
@@ -89,7 +84,7 @@ Namespace = NamespaceMetaclass('Namespace', (object, ), {
 
 class HtmlTag(Tag):
 
-    def unicode(self, indent=2):
+    def str(self, indent=2):
         l = []
         HtmlVisitor(l.append, indent, shortempty=False).visit(self)
         return u("").join(l)
@@ -100,7 +95,7 @@ class HtmlTag(Tag):
 class html(Namespace):
     __tagclass__ = HtmlTag
     __stickyname__ = True
-    __tagspec__ = dict([(x, 1) for x in (
+    __tagspec__ = {x: 1 for x in (
         'a,abbr,acronym,address,applet,area,b,bdo,big,blink,'
         'blockquote,body,br,button,caption,center,cite,code,col,'
         'colgroup,comment,dd,del,dfn,dir,div,dl,dt,em,embed,'
@@ -111,9 +106,9 @@ class html(Namespace):
         'select,small,span,strike,strong,style,sub,sup,table,'
         'tbody,td,textarea,tfoot,th,thead,title,tr,tt,u,ul,xmp,'
         'base,basefont,frame,hr,isindex,param,samp,var'
-    ).split(',') if x])
+    ).split(',') if x}
 
-    class Style(object):
+    class Style:
 
         def __init__(self, **kw):
             for x, y in kw.items():
@@ -121,7 +116,7 @@ class html(Namespace):
                 setattr(self, x, y)
 
 
-class raw(object):
+class raw:
     """just a box that can contain a unicode string that will be
     included directly in the output"""
 
@@ -129,7 +124,7 @@ class raw(object):
         self.uniobj = uniobj
 
 
-class SimpleUnicodeVisitor(object):
+class SimpleUnicodeVisitor:
     """ recursive visitor to write unicode. """
 
     def __init__(self, write, indent=0, curindent=0, shortempty=True):
@@ -160,7 +155,7 @@ class SimpleUnicodeVisitor(object):
     # to avoid clashes with the tag name object
     def __object(self, obj):
         # self.write(obj)
-        self.write(escape(unicode(obj)))
+        self.write(escape(str(obj)))
 
     def raw(self, obj):
         self.write(obj.uniobj)
@@ -217,8 +212,8 @@ class SimpleUnicodeVisitor(object):
             if isinstance(value, raw):
                 insert = value.uniobj
             else:
-                insert = escape(unicode(value))
-            return ' %s="%s"' % (name, insert)
+                insert = escape(str(value))
+            return ' {}="{}"'.format(name, insert)
 
     def getstyle(self, tag):
         """ return attribute list suitable for styling. """
@@ -241,20 +236,20 @@ class SimpleUnicodeVisitor(object):
 
 class HtmlVisitor(SimpleUnicodeVisitor):
 
-    single = dict([(x, 1) for x in
+    single = {x: 1 for x in
                    ('br,img,area,param,col,hr,meta,link,base,'
-                    'input,frame').split(',')])
-    inline = dict([(x, 1) for x in
+                    'input,frame').split(',')}
+    inline = {x: 1 for x in
                    ('a abbr acronym b basefont bdo big br cite code dfn em font '
                     'i img input kbd label q s samp select small span strike '
-                    'strong sub sup textarea tt u var'.split(' '))])
+                    'strong sub sup textarea tt u var'.split(' '))}
 
     def repr_attribute(self, attrs, name):
         if name == 'class_':
             value = getattr(attrs, name)
             if value is None:
                 return
-        return super(HtmlVisitor, self).repr_attribute(attrs, name)
+        return super().repr_attribute(attrs, name)
 
     def _issingleton(self, tagname):
         return tagname in self.single
@@ -270,14 +265,14 @@ class _escape:
             u('"'): u('&quot;'), u('<'): u('&lt;'), u('>'): u('&gt;'),
             u('&'): u('&amp;'), u("'"): u('&apos;'),
         }
-        self.charef_rex = re.compile(u("|").join(self.escape.keys()))
+        self.charef_rex = re.compile(u("|").join(list(self.escape.keys())))
 
     def _replacer(self, match):
         return self.escape[match.group(0)]
 
     def __call__(self, ustring):
         """ xml-escape the given unicode string. """
-        ustring = unicode(ustring)
+        ustring = str(ustring)
         return self.charef_rex.sub(self._replacer, ustring)
 
 escape = _escape()
diff --git a/testing/mozbase/mozlog/mozlog/formatters/machformatter.py b/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
index f8f1abc256..3dc005e4bd 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
@@ -10,7 +10,7 @@ try:
 except ImportError:
     blessings = None
 
-import base
+from . import base
 from .process import strstatus
 
 
@@ -20,7 +20,7 @@ def format_seconds(total):
     return '%2d:%05.2f' % (minutes, seconds)
 
 
-class NullTerminal(object):
+class NullTerminal:
 
     def __getattr__(self, name):
         return self._id
@@ -91,7 +91,7 @@ class MachFormatter(base.BaseFormatter):
             if color is not None:
                 action = color(action)
 
-        return "%s %s: %s %s\n" % (time, action, thread, s)
+        return "{} {}: {} {}\n".format(time, action, thread, s)
 
     def _get_test_id(self, data):
         test_id = data.get("test")
@@ -100,7 +100,7 @@ class MachFormatter(base.BaseFormatter):
         return test_id
 
     def _get_file_name(self, test_id):
-        if isinstance(test_id, (str, unicode)):
+        if isinstance(test_id, (str, str)):
             return test_id
 
         if isinstance(test_id, tuple):
@@ -160,14 +160,14 @@ class MachFormatter(base.BaseFormatter):
                     for name, status, expected, message in results:
                         if name is None:
                             name = "[Parent]"
-                        rv.append("%s %s" % (self.format_expected(status, expected), name))
+                        rv.append("{} {}".format(self.format_expected(status, expected), name))
             else:
                 for test_id, results in self.summary_unexpected:
                     test = self._get_file_name(test_id)
                     assert len(results) == 1
                     name, status, expected, messge = results[0]
                     assert name is None
-                    rv.append("%s %s" % (self.format_expected(status, expected), test))
+                    rv.append("{} {}".format(self.format_expected(status, expected), test))
 
         return "\n".join(rv)
 
@@ -181,11 +181,11 @@ class MachFormatter(base.BaseFormatter):
         if expected in ("PASS", "OK"):
             return color(status)
 
-        return color("%s expected %s" % (status, expected))
+        return color("{} expected {}".format(status, expected))
 
     def test_start(self, data):
         self.summary_values["tests"] += 1
-        return "%s" % (self._get_test_id(data),)
+        return "{}".format(self._get_test_id(data))
 
     def test_end(self, data):
         subtests = self._get_subtest_data(data)
@@ -222,7 +222,7 @@ class MachFormatter(base.BaseFormatter):
                 data["status"], expected_str, subtests["pass"], subtests["count"],
                 len(unexpected))
         else:
-            rv = "%s%s" % (data["status"], expected_str)
+            rv = "{}{}".format(data["status"], expected_str)
 
         if unexpected:
             rv += "\n"
@@ -232,7 +232,7 @@ class MachFormatter(base.BaseFormatter):
                 for name, status, expected, message in unexpected:
                     if name is None:
                         name = "[Parent]"
-                    expected_str = "Expected %s, got %s" % (expected, status)
+                    expected_str = "Expected {}, got {}".format(expected, status)
                     rv += "%s\n" % ("\n".join([name, "-" * len(name), expected_str, message]))
                 rv = rv[:-1]
         return rv
@@ -292,9 +292,9 @@ class MachFormatter(base.BaseFormatter):
 
         if "command" in data and data["process"] not in self._known_pids:
             self._known_pids.add(data["process"])
-            rv.append('(pid:%s) Full command: %s' % (data["process"], data["command"]))
+            rv.append('(pid:{}) Full command: {}'.format(data["process"], data["command"]))
 
-        rv.append('(pid:%s) "%s"' % (data["process"], data["data"]))
+        rv.append('(pid:{}) "{}"'.format(data["process"], data["data"]))
         return "\n".join(rv)
 
     def crash(self, data):
@@ -334,11 +334,11 @@ class MachFormatter(base.BaseFormatter):
         rv = "Started process `%s`" % data['process']
         desc = data.get('command')
         if desc:
-            rv = '%s (%s)' % (rv, desc)
+            rv = '{} ({})'.format(rv, desc)
         return rv
 
     def process_exit(self, data):
-        return "%s: %s" % (data['process'], strstatus(data['exitcode']))
+        return "{}: {}".format(data['process'], strstatus(data['exitcode']))
 
     def log(self, data):
         level = data.get("level").upper()
@@ -354,7 +354,7 @@ class MachFormatter(base.BaseFormatter):
         if data.get('component'):
             rv = " ".join([data["component"], level, data["message"]])
         else:
-            rv = "%s %s" % (level, data["message"])
+            rv = "{} {}".format(level, data["message"])
 
         if "stack" in data:
             rv += "\n%s" % data["stack"]
diff --git a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
index 71152d4558..81d1f0e643 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
@@ -61,7 +61,7 @@ class TbplFormatter(BaseFormatter):
 
     def _log(self, data):
         if data.get('component'):
-            message = "%s %s" % (data["component"], data["message"])
+            message = "{} {}".format(data["component"], data["message"])
         else:
             message = data["message"]
 
@@ -78,12 +78,12 @@ class TbplFormatter(BaseFormatter):
     def process_start(self, data):
         msg = "TEST-INFO | started process %s" % data['process']
         if 'command' in data:
-            msg = '%s (%s)' % (msg, data['command'])
+            msg = '{} ({})'.format(msg, data['command'])
         return msg + '\n'
 
     @output_subtests
     def process_exit(self, data):
-        return "TEST-INFO | %s: %s\n" % (data['process'],
+        return "TEST-INFO | {}: {}\n".format(data['process'],
                                          strstatus(data['exitcode']))
 
     @output_subtests
@@ -91,7 +91,7 @@ class TbplFormatter(BaseFormatter):
         id = data["test"] if "test" in data else "pid: %s" % data["process"]
 
         signature = data["signature"] if data["signature"] else "unknown top frame"
-        rv = ["PROCESS-CRASH | %s | application crashed [%s]" % (id, signature)]
+        rv = ["PROCESS-CRASH | {} | application crashed [{}]".format(id, signature)]
 
         if data.get("minidump_path"):
             rv.append("Crash dump filename: %s" % data["minidump_path"])
@@ -149,7 +149,7 @@ class TbplFormatter(BaseFormatter):
         if "expected" in data:
             if not message:
                 message = "- expected %s" % data["expected"]
-            failure_line = "TEST-UNEXPECTED-%s | %s | %s %s\n" % (
+            failure_line = "TEST-UNEXPECTED-{} | {} | {} {}\n".format(
                 data["status"], data["test"], data["subtest"],
                 message)
             if data["expected"] != "PASS":
@@ -157,7 +157,7 @@ class TbplFormatter(BaseFormatter):
                 return failure_line + info_line
             return failure_line
 
-        return "TEST-%s | %s | %s %s\n" % (
+        return "TEST-{} | {} | {} {}\n".format(
             data["status"], data["test"], data["subtest"],
             message)
 
@@ -200,14 +200,14 @@ class TbplFormatter(BaseFormatter):
                     message += "\nREFTEST   IMAGE: data:image/png;base64,%(image1)s" \
                                % screenshots[0]["screenshot"]
 
-            failure_line = "TEST-UNEXPECTED-%s | %s | %s\n" % (
+            failure_line = "TEST-UNEXPECTED-{} | {} | {}\n".format(
                 data["status"], test_id, message)
 
             if data["expected"] not in ("PASS", "OK"):
                 expected_msg = "expected %s | " % data["expected"]
             else:
                 expected_msg = ""
-            info_line = "TEST-INFO %s%s\n" % (expected_msg, duration_msg)
+            info_line = "TEST-INFO {}{}\n".format(expected_msg, duration_msg)
 
             return failure_line + info_line
 
@@ -224,7 +224,7 @@ class TbplFormatter(BaseFormatter):
         return "SUITE-END | took %is\n" % time
 
     def test_id(self, test_id):
-        if isinstance(test_id, (str, unicode)):
+        if isinstance(test_id, (str, str)):
             return test_id
         else:
             return tuple(test_id)
diff --git a/testing/mozbase/mozlog/mozlog/formatters/unittest.py b/testing/mozbase/mozlog/mozlog/formatters/unittest.py
index 254205eae5..7618d25758 100755
--- a/testing/mozbase/mozlog/mozlog/formatters/unittest.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/unittest.py
@@ -3,7 +3,7 @@
 # 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/.
 
-import base
+from . import base
 
 
 class UnittestFormatter(base.BaseFormatter):
diff --git a/testing/mozbase/mozlog/mozlog/formatters/xunit.py b/testing/mozbase/mozlog/mozlog/formatters/xunit.py
index 3930afa3e5..fcf42cbe0b 100644
--- a/testing/mozbase/mozlog/mozlog/formatters/xunit.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/xunit.py
@@ -1,13 +1,13 @@
 import types
 from xml.etree import ElementTree
 
-import base
+from . import base
 
 
 def format_test_id(test_id):
     """Take a test id and return something that looks a bit like
     a class path"""
-    if type(test_id) not in types.StringTypes:
+    if type(test_id) not in (str,):
         # Not sure how to deal with reftests yet
         raise NotImplementedError
 
@@ -75,8 +75,8 @@ class XUnitFormatter(base.BaseFormatter):
                 result = ElementTree.SubElement(test, "failure")
                 self.failures += 1
 
-            result.attrib["message"] = "Expected %s, got %s" % (data["expected"], data["status"])
-            result.text = '%s\n%s' % (data.get('stack', ''), data.get('message', ''))
+            result.attrib["message"] = "Expected {}, got {}".format(data["expected"], data["status"])
+            result.text = '{}\n{}'.format(data.get('stack', ''), data.get('message', ''))
 
         elif data["status"] == "SKIP":
             result = ElementTree.SubElement(test, "skipped")
diff --git a/testing/mozbase/mozlog/mozlog/handlers/base.py b/testing/mozbase/mozlog/mozlog/handlers/base.py
index be4df21f9f..0cfa31727d 100644
--- a/testing/mozbase/mozlog/mozlog/handlers/base.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/base.py
@@ -8,7 +8,7 @@ import codecs
 from ..structuredlog import log_levels
 
 
-class BaseHandler(object):
+class BaseHandler:
     """A base handler providing message handling facilities to
     derived classes.
 
@@ -95,7 +95,7 @@ class StreamHandler(BaseHandler):
         if not formatted:
             return
         with self._lock:
-            if isinstance(formatted, unicode):
+            if isinstance(formatted, str):
                 self.stream.write(formatted.encode("utf-8", "replace"))
             elif isinstance(formatted, str):
                 self.stream.write(formatted)
diff --git a/testing/mozbase/mozlog/mozlog/handlers/statushandler.py b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
index b5aeb1b537..b762eaeb44 100644
--- a/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
@@ -15,7 +15,7 @@ RunSummary = namedtuple("RunSummary",
                          "action_counts"))
 
 
-class StatusHandler(object):
+class StatusHandler:
     """A handler used to determine an overall status for a test run according
     to a sequence of log messages."""
 
diff --git a/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py b/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
index 5bedfb9abe..fd21570dab 100644
--- a/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
@@ -19,7 +19,7 @@ class ValgrindHandler(BaseHandler):
             self.inner(tmp)
 
 
-class ValgrindFilter(object):
+class ValgrindFilter:
     '''
     A class for handling Valgrind output.
 
@@ -123,14 +123,14 @@ class ValgrindFilter(object):
                 # fields from the incoming message, since there's nowhere
                 # else to get them from.
                 output_message = {  # Mandatory fields
-                    u"action": "valgrind_error",
-                    u"time":   msg["time"],
-                    u"thread": msg["thread"],
-                    u"pid":    msg["pid"],
-                    u"source": msg["source"],
+                    "action": "valgrind_error",
+                    "time":   msg["time"],
+                    "thread": msg["thread"],
+                    "pid":    msg["pid"],
+                    "source": msg["source"],
                     # valgrind_error specific fields
-                    u"primary":   self.curr_failure_msg,
-                    u"secondary": self.buffered_lines}
+                    "primary":   self.curr_failure_msg,
+                    "secondary": self.buffered_lines}
                 self.curr_failure_msg = ""
                 self.buffered_lines = []
 
diff --git a/testing/mozbase/mozlog/mozlog/logtypes.py b/testing/mozbase/mozlog/mozlog/logtypes.py
index d5ebff93cc..4ab4f86d84 100644
--- a/testing/mozbase/mozlog/mozlog/logtypes.py
+++ b/testing/mozbase/mozlog/mozlog/logtypes.py
@@ -7,7 +7,7 @@ missing = object()
 no_default = object()
 
 
-class log_action(object):
+class log_action:
 
     def __init__(self, *args):
         self.args = {}
@@ -83,7 +83,7 @@ class log_action(object):
             if name not in values:
                 values[name] = self.args[name].default
 
-        for key, value in values.iteritems():
+        for key, value in values.items():
             if key in self.args:
                 out_value = self.args[key](value)
                 if out_value is not missing:
@@ -94,12 +94,12 @@ class log_action(object):
         return data
 
     def convert_known(self, **kwargs):
-        known_kwargs = {name: value for name, value in kwargs.iteritems()
+        known_kwargs = {name: value for name, value in kwargs.items()
                         if name in self.args}
         return self.convert(**known_kwargs)
 
 
-class DataType(object):
+class DataType:
 
     def __init__(self, name, default=no_default, optional=False):
         self.name = name
@@ -126,17 +126,17 @@ class DataType(object):
 class Unicode(DataType):
 
     def convert(self, data):
-        if isinstance(data, unicode):
+        if isinstance(data, str):
             return data
         if isinstance(data, str):
             return data.decode("utf8", "replace")
-        return unicode(data)
+        return str(data)
 
 
 class TestId(DataType):
 
     def convert(self, data):
-        if isinstance(data, unicode):
+        if isinstance(data, str):
             return data
         elif isinstance(data, bytes):
             return data.decode("utf-8", "replace")
diff --git a/testing/mozbase/mozlog/mozlog/proxy.py b/testing/mozbase/mozlog/mozlog/proxy.py
index 44ce242256..0c69728220 100644
--- a/testing/mozbase/mozlog/mozlog/proxy.py
+++ b/testing/mozbase/mozlog/mozlog/proxy.py
@@ -5,7 +5,7 @@
 from .structuredlog import get_default_logger
 
 
-class ProxyLogger(object):
+class ProxyLogger:
     """
     A ProxyLogger behaves like a
     :class:`mozlog.structuredlog.StructuredLogger`.
diff --git a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
index 811ee38e38..03090fe8a9 100644
--- a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
+++ b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
@@ -12,15 +12,15 @@ def pytest_addoption(parser):
     # Pytest's parser doesn't have the add_argument_group method Mozlog expects.
     group = parser.getgroup('mozlog')
 
-    for name, (_class, _help) in mozlog.commandline.log_formatters.iteritems():
-        group.addoption('--log-{0}'.format(name), action='append', help=_help)
+    for name, (_class, _help) in mozlog.commandline.log_formatters.items():
+        group.addoption('--log-{}'.format(name), action='append', help=_help)
 
-    formatter_options = mozlog.commandline.fmt_options.iteritems()
+    formatter_options = mozlog.commandline.fmt_options.items()
     for name, (_class, _help, formatters, action) in formatter_options:
         for formatter in formatters:
             if formatter in mozlog.commandline.log_formatters:
                 group.addoption(
-                    '--log-{0}-{1}'.format(formatter, name),
+                    '--log-{}-{}'.format(formatter, name),
                     action=action,
                     help=_help)
 
@@ -31,7 +31,7 @@ def pytest_configure(config):
         config.pluginmanager.register(MozLog())
 
 
-class MozLog(object):
+class MozLog:
 
     def __init__(self):
         self.results = {}
@@ -79,7 +79,7 @@ class MozLog(object):
         elif report.failed:
             status = 'FAIL' if report.when == 'call' else 'ERROR'
             crash = report.longrepr.reprcrash  # here longrepr is a ReprExceptionInfo
-            message = "{0} (line {1})".format(crash.message, crash.lineno)
+            message = "{} (line {})".format(crash.message, crash.lineno)
             stack = report.longrepr.reprtraceback
         elif report.skipped:  # indicates true skip
             status = expected = 'SKIP'
diff --git a/testing/mozbase/mozlog/mozlog/reader.py b/testing/mozbase/mozlog/mozlog/reader.py
index c00ec6d383..00a4343ee7 100644
--- a/testing/mozbase/mozlog/mozlog/reader.py
+++ b/testing/mozbase/mozlog/mozlog/reader.py
@@ -50,7 +50,7 @@ def each_log(log_iter, action_map):
             action_map[item["action"]](item)
 
 
-class LogHandler(object):
+class LogHandler:
     """Base class for objects that act as log handlers. A handler is a callable
     that takes a log entry as the only argument.
 
diff --git a/testing/mozbase/mozlog/mozlog/scripts/__init__.py b/testing/mozbase/mozlog/mozlog/scripts/__init__.py
index 53f9146c92..869fb81360 100644
--- a/testing/mozbase/mozlog/mozlog/scripts/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/__init__.py
@@ -1,9 +1,9 @@
 #!/usr/bin/env python
 
 import argparse
-import unstable
-import format as formatlog
-import logmerge
+from . import unstable
+from . import format as formatlog
+from . import logmerge
 
 
 def get_parser():
@@ -16,7 +16,7 @@ def get_parser():
 
     sub_parser = parser.add_subparsers(title='Subcommands')
 
-    for command, (parser_func, main_func) in commands.iteritems():
+    for command, (parser_func, main_func) in commands.items():
         parent = parser_func(False)
         command_parser = sub_parser.add_parser(command,
                                                description=parent.description,
diff --git a/testing/mozbase/mozlog/mozlog/scripts/format.py b/testing/mozbase/mozlog/mozlog/scripts/format.py
index 1644e4b956..627ff104a4 100644
--- a/testing/mozbase/mozlog/mozlog/scripts/format.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/format.py
@@ -12,7 +12,7 @@ def get_parser(add_help=True):
                         help="Filename to read from, defaults to stdin")
     parser.add_argument("--output", action="store", default=None,
                         help="Filename to write to, defaults to stdout")
-    parser.add_argument("format", choices=commandline.log_formatters.keys(),
+    parser.add_argument("format", choices=list(commandline.log_formatters.keys()),
                         help="Format to use")
     return parser
 
diff --git a/testing/mozbase/mozlog/mozlog/scripts/logmerge.py b/testing/mozbase/mozlog/mozlog/scripts/logmerge.py
index 1185dc6055..89ea8a2ad5 100644
--- a/testing/mozbase/mozlog/mozlog/scripts/logmerge.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/logmerge.py
@@ -1,4 +1,3 @@
-from __future__ import print_function
 import argparse
 import json
 import os
@@ -61,7 +60,7 @@ def main(**kwargs):
         output = sys.stdout
     else:
         output = open(kwargs["output"], "w")
-    readers = [read(open(filename, 'r')) for filename in kwargs["files"]]
+    readers = [read(open(filename)) for filename in kwargs["files"]]
     start_events = [process_until_suite_start(reader, output) for reader in readers]
     validate_start_events(start_events)
     merged_start_event = merge_start_events(start_events)
diff --git a/testing/mozbase/mozlog/mozlog/scripts/unstable.py b/testing/mozbase/mozlog/mozlog/scripts/unstable.py
index 2b31bba52e..9839c175e4 100644
--- a/testing/mozbase/mozlog/mozlog/scripts/unstable.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/unstable.py
@@ -73,17 +73,17 @@ def group_results(data):
 def print_results(data):
     for run_info, tests in data.iteritems():
         run_str = " ".join("%s:%s" % (k, v) for k, v in run_info) if run_info else "No Run Info"
-        print run_str
-        print "=" * len(run_str)
+        print(run_str)
+        print("=" * len(run_str))
         print_run(tests)
 
 
 def print_run(tests):
     for test, subtests in sorted(tests.items()):
-        print "\n" + str(test)
-        print "-" * len(test)
+        print("\n" + str(test))
+        print("-" * len(test))
         for name, results in subtests.iteritems():
-            print "[%s]: %s" % (name if name is not None else "",
+            print("[%s]: %s" % (name if name is not None else "",)
                                 " ".join("%s (%i)" % (k, v) for k, v in results.iteritems()))
 
 
@@ -106,7 +106,7 @@ def main(**kwargs):
         unstable = group_results(unstable)
 
     if kwargs["json"]:
-        print json.dumps(unstable)
+        print(json.dumps(unstable))
     else:
         if not kwargs["group"]:
             print_results(unstable)
diff --git a/testing/mozbase/mozlog/mozlog/stdadapter.py b/testing/mozbase/mozlog/mozlog/stdadapter.py
index fc967c0a61..d4459d9c75 100644
--- a/testing/mozbase/mozlog/mozlog/stdadapter.py
+++ b/testing/mozbase/mozlog/mozlog/stdadapter.py
@@ -1,6 +1,6 @@
 import logging
 
-from structuredlog import StructuredLogger, log_levels
+from .structuredlog import StructuredLogger, log_levels
 
 
 class UnstructuredHandler(logging.Handler):
@@ -20,7 +20,7 @@ class UnstructuredHandler(logging.Handler):
         self.emit(record)
 
 
-class LoggingWrapper(object):
+class LoggingWrapper:
 
     def __init__(self, wrapped):
         self.wrapped = wrapped
diff --git a/testing/mozbase/mozlog/mozlog/structuredlog.py b/testing/mozbase/mozlog/mozlog/structuredlog.py
index fb41f2112e..45e7b32ff6 100644
--- a/testing/mozbase/mozlog/mozlog/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structuredlog.py
@@ -2,7 +2,6 @@
 # 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 unicode_literals
 
 from multiprocessing import current_process
 from threading import current_thread, Lock
@@ -11,8 +10,8 @@ import sys
 import time
 import traceback
 
-from logtypes import Unicode, TestId, Status, SubStatus, Dict, List, Int, Any, Tuple
-from logtypes import log_action, convertor_registry
+from .logtypes import Unicode, TestId, Status, SubStatus, Dict, List, Int, Any, Tuple
+from .logtypes import log_action, convertor_registry
 
 """Structured Logging for recording test results.
 
@@ -92,8 +91,8 @@ def set_default_logger(default_logger):
 
     _default_logger_name = default_logger.name
 
-log_levels = dict((k.upper(), v) for v, k in
-                  enumerate(["critical", "error", "warning", "info", "debug"]))
+log_levels = {k.upper(): v for v, k in
+                  enumerate(["critical", "error", "warning", "info", "debug"])}
 
 lint_levels = ["ERROR", "WARNING"]
 
@@ -103,7 +102,7 @@ def log_actions():
     return set(convertor_registry.keys())
 
 
-class LoggerState(object):
+class LoggerState:
 
     def __init__(self):
         self.handlers = []
@@ -112,13 +111,13 @@ class LoggerState(object):
         self.component_states = {}
 
 
-class ComponentState(object):
+class ComponentState:
 
     def __init__(self):
         self.filter_ = None
 
 
-class StructuredLogger(object):
+class StructuredLogger:
     _lock = Lock()
     _logger_states = {}
     """Create a structured logger with the given name
@@ -222,8 +221,8 @@ class StructuredLogger(object):
                 except Exception:
                     # Write the exception details directly to stderr because
                     # log() would call this method again which is currently locked.
-                    print >> sys.__stderr__, '%s: Failure calling log handler:' % __name__
-                    print >> sys.__stderr__, traceback.format_exc()
+                    print('%s: Failure calling log handler:' % __name__, file=sys.__stderr__)
+                    print(traceback.format_exc(), file=sys.__stderr__)
 
     def _make_log_data(self, action, data):
         all_data = {"action": action,
@@ -433,7 +432,7 @@ def _log_func(level_name):
                 exc_info = sys.exc_info()
             if exc_info != (None, None, None):
                 bt = traceback.format_exception(*exc_info)
-                data["stack"] = u"\n".join(bt)
+                data["stack"] = "\n".join(bt)
 
         data["level"] = level_name
         self._log_data("log", data)
@@ -490,7 +489,7 @@ for level_name in lint_levels:
     setattr(StructuredLogger, name, _lint_func(level_name))
 
 
-class StructuredLogFileLike(object):
+class StructuredLogFileLike:
     """Wrapper for file-like objects to redirect writes to logger
     instead. Each call to `write` becomes a single log entry of type `log`.
 
@@ -514,7 +513,7 @@ class StructuredLogFileLike(object):
         if data.endswith("\r"):
             data = data[:-1]
         if self.prefix is not None:
-            data = "%s: %s" % (self.prefix, data)
+            data = "{}: {}".format(self.prefix, data)
         self.log_func(data)
 
     def flush(self):
diff --git a/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py b/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
index 41a67cf09e..5700af1000 100644
--- a/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
@@ -8,7 +8,7 @@ from .logger import (
 )
 
 
-class LoggingMixin(object):
+class LoggingMixin:
     """Expose a subset of logging functions to an inheriting class."""
 
     def set_logger(self, logger_instance=None, name=None):
diff --git a/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py b/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
index d567301805..77d08f1ed9 100644
--- a/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
@@ -2,21 +2,21 @@
 # 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/.
 
-import SocketServer
+import socketserver
 import socket
 import json
 
 
-class LogMessageServer(SocketServer.TCPServer):
+class LogMessageServer(socketserver.TCPServer):
 
     def __init__(self, server_address, logger, message_callback=None, timeout=3):
-        SocketServer.TCPServer.__init__(self, server_address, LogMessageHandler)
+        socketserver.TCPServer.__init__(self, server_address, LogMessageHandler)
         self._logger = logger
         self._message_callback = message_callback
         self.timeout = timeout
 
 
-class LogMessageHandler(SocketServer.BaseRequestHandler):
+class LogMessageHandler(socketserver.BaseRequestHandler):
     """Processes output from a connected log source, logging to an
     existing logger upon receipt of a well-formed log messsage."""
 
diff --git a/testing/mozbase/mozlog/tests/test_logger.py b/testing/mozbase/mozlog/tests/test_logger.py
index 30f4eb5699..ea35624959 100644
--- a/testing/mozbase/mozlog/tests/test_logger.py
+++ b/testing/mozbase/mozlog/tests/test_logger.py
@@ -80,7 +80,7 @@ class TestStructuredLogging(unittest.TestCase):
         The actual message should contain no fields other than the timestamp
         field and those present in expected."""
 
-        self.assertTrue(isinstance(actual['_time'], (int, long)))
+        self.assertTrue(isinstance(actual['_time'], int))
 
         for k, v in expected.items():
             self.assertEqual(v, actual[k])
diff --git a/testing/mozbase/mozlog/tests/test_structured.py b/testing/mozbase/mozlog/tests/test_structured.py
index ab4b5f5826..a7b621ca7a 100644
--- a/testing/mozbase/mozlog/tests/test_structured.py
+++ b/testing/mozbase/mozlog/tests/test_structured.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import argparse
 import json
 import optparse
@@ -19,9 +18,11 @@ from mozlog import (
     handlers,
     formatters,
 )
+import six
+unichr = chr
 
 
-class TestHandler(object):
+class TestHandler:
 
     def __init__(self):
         self.items = []
@@ -55,20 +56,20 @@ class BaseStructuredTest(unittest.TestCase):
         all_expected = {"pid": os.getpid(),
                         "thread": "MainThread",
                         "source": "test"}
-        specials = set(["time"])
+        specials = {"time"}
 
         all_expected.update(expected)
-        for key, value in all_expected.iteritems():
+        for key, value in all_expected.items():
             self.assertEqual(actual[key], value)
 
-        self.assertEquals(set(all_expected.keys()) |
+        self.assertEqual(set(all_expected.keys()) |
                           specials, set(actual.keys()))
 
 
 class TestStatusHandler(BaseStructuredTest):
 
     def setUp(self):
-        super(TestStatusHandler, self).setUp()
+        super().setUp()
         self.handler = handlers.StatusHandler()
         self.logger.add_handler(self.handler)
 
@@ -253,8 +254,8 @@ class TestStructuredLog(BaseStructuredTest):
                                 "test": "test2"})
         self.logger.test_end("test2", "PASS", expected="PASS")
         last_item = self.pop_last_item()
-        self.assertEquals(last_item["action"], "log")
-        self.assertEquals(last_item["level"], "ERROR")
+        self.assertEqual(last_item["action"], "log")
+        self.assertEqual(last_item["level"], "ERROR")
         self.assertTrue(last_item["message"].startswith(
             "test_end for test2 logged while not in progress. Logged with data: {"))
         self.logger.suite_end()
@@ -265,8 +266,8 @@ class TestStructuredLog(BaseStructuredTest):
                                 "tests": []})
         self.logger.suite_start([])
         last_item = self.pop_last_item()
-        self.assertEquals(last_item["action"], "log")
-        self.assertEquals(last_item["level"], "ERROR")
+        self.assertEqual(last_item["action"], "log")
+        self.assertEqual(last_item["level"], "ERROR")
         self.logger.suite_end()
 
     def test_suite_end_no_start(self):
@@ -277,16 +278,16 @@ class TestStructuredLog(BaseStructuredTest):
         self.assert_log_equals({"action": "suite_end"})
         self.logger.suite_end()
         last_item = self.pop_last_item()
-        self.assertEquals(last_item["action"], "log")
-        self.assertEquals(last_item["level"], "ERROR")
+        self.assertEqual(last_item["action"], "log")
+        self.assertEqual(last_item["level"], "ERROR")
 
     def test_multiple_loggers_suite_start(self):
         logger1 = structuredlog.StructuredLogger("test")
         self.logger.suite_start([])
         logger1.suite_start([])
         last_item = self.pop_last_item()
-        self.assertEquals(last_item["action"], "log")
-        self.assertEquals(last_item["level"], "ERROR")
+        self.assertEqual(last_item["action"], "log")
+        self.assertEqual(last_item["level"], "ERROR")
 
     def test_multiple_loggers_test_start(self):
         logger1 = structuredlog.StructuredLogger("test")
@@ -294,8 +295,8 @@ class TestStructuredLog(BaseStructuredTest):
         self.logger.test_start("test")
         logger1.test_start("test")
         last_item = self.pop_last_item()
-        self.assertEquals(last_item["action"], "log")
-        self.assertEquals(last_item["level"], "ERROR")
+        self.assertEqual(last_item["action"], "log")
+        self.assertEqual(last_item["level"], "ERROR")
 
     def test_process(self):
         self.logger.process_output(1234, "test output")
@@ -407,10 +408,10 @@ class TestTypeConversions(BaseStructuredTest):
     def test_tuple(self):
         self.logger.suite_start([])
         self.logger.test_start(("\xf0\x90\x8d\x84\xf0\x90\x8c\xb4\xf0\x90\x8d\x83\xf0\x90\x8d\x84",
-                                42, u"\u16a4"))
+                                42, "\u16a4"))
         self.assert_log_equals({"action": "test_start",
-                                "test": (u'\U00010344\U00010334\U00010343\U00010344',
-                                         u"42", u"\u16a4")})
+                                "test": ('\U00010344\U00010334\U00010343\U00010344',
+                                         "42", "\u16a4")})
         self.logger.suite_end()
 
     def test_non_string_messages(self):
@@ -434,7 +435,7 @@ class TestTypeConversions(BaseStructuredTest):
             self.logger.info("☺")
             logfile.seek(0)
             data = logfile.readlines()[-1].strip()
-            self.assertEquals(data, "☺")
+            self.assertEqual(data, "☺")
             self.logger.suite_end()
 
     def test_arguments(self):
@@ -784,7 +785,7 @@ class TestXUnitFormatter(FormatterTest):
         self.logger.suite_end()
 
         root = self.log_as_xml()
-        self.assertEquals('Expected OK, got FAIL', root.find(
+        self.assertEqual('Expected OK, got FAIL', root.find(
             'testcase/failure').get('message'))
 
     def test_suite_attrs(self):
@@ -858,7 +859,7 @@ class TestCommandline(unittest.TestCase):
     def test_setup_logging_optparse_unicode(self):
         parser = optparse.OptionParser()
         commandline.add_logging_group(parser)
-        args, _ = parser.parse_args([u"--log-raw=-"])
+        args, _ = parser.parse_args(["--log-raw=-"])
         logger = commandline.setup_logging("test_optparse_unicode", args, {})
         self.assertEqual(len(logger.handlers), 1)
         self.assertEqual(logger.handlers[0].stream, sys.stdout)
@@ -924,13 +925,13 @@ class TestBuffer(BaseStructuredTest):
         all_expected = {"pid": os.getpid(),
                         "thread": "MainThread",
                         "source": "testBuffer"}
-        specials = set(["time"])
+        specials = {"time"}
 
         all_expected.update(expected)
-        for key, value in all_expected.iteritems():
+        for key, value in all_expected.items():
             self.assertEqual(actual[key], value)
 
-        self.assertEquals(set(all_expected.keys()) |
+        self.assertEqual(set(all_expected.keys()) |
                           specials, set(actual.keys()))
 
     def setUp(self):
@@ -985,11 +986,11 @@ class TestBuffer(BaseStructuredTest):
                                 "test": "test1"})
 
         # The buffer's actual size never grows beyond the specified limit.
-        self.assertEquals(len(self.handler._buffer), 4)
+        self.assertEqual(len(self.handler._buffer), 4)
 
         self.logger.test_status("test1", "sub8", status="FAIL")
         # The number of messages deleted comes back in a list.
-        self.assertEquals([4], self.logger.send_message("buffer", "flush"))
+        self.assertEqual([4], self.logger.send_message("buffer", "flush"))
 
         # When the buffer is dumped, the failure is the last thing logged
         self.assert_log_equals({"action": "test_status",
@@ -1025,7 +1026,7 @@ class TestReader(unittest.TestCase):
                 {"action": "action_1", "data": "data_1"}]
 
         f = self.to_file_like(data)
-        self.assertEquals(data, list(reader.read(f)))
+        self.assertEqual(data, list(reader.read(f)))
 
     def test_imap_log(self):
         data = [{"action": "action_0", "data": "data_0"},
@@ -1042,7 +1043,7 @@ class TestReader(unittest.TestCase):
         res_iter = reader.imap_log(reader.read(f),
                                    {"action_0": f_action_0,
                                     "action_1": f_action_1})
-        self.assertEquals([("action_0", "data_0"), ("action_1", "data_1")],
+        self.assertEqual([("action_0", "data_0"), ("action_1", "data_1")],
                           list(res_iter))
 
     def test_each_log(self):
@@ -1064,7 +1065,7 @@ class TestReader(unittest.TestCase):
                         {"action_0": f_action_0,
                          "action_1": f_action_1})
 
-        self.assertEquals({"action_0": 1, "action_1": 2}, count)
+        self.assertEqual({"action_0": 1, "action_1": 2}, count)
 
     def test_handler(self):
         data = [{"action": "action_0", "data": "data_0"},
@@ -1091,8 +1092,8 @@ class TestReader(unittest.TestCase):
         handler = ReaderTestHandler()
         reader.handle_log(reader.read(f), handler)
 
-        self.assertEquals(handler.action_0_count, 1)
-        self.assertEquals(handler.action_1_count, 1)
+        self.assertEqual(handler.action_0_count, 1)
+        self.assertEqual(handler.action_1_count, 1)
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/testing/mozbase/moznetwork/moznetwork/__init__.py b/testing/mozbase/moznetwork/moznetwork/__init__.py
index df2097cb02..e3423e71ac 100644
--- a/testing/mozbase/moznetwork/moznetwork/__init__.py
+++ b/testing/mozbase/moznetwork/moznetwork/__init__.py
@@ -14,13 +14,13 @@ Example usage:
 
   try:
       ip = moznetwork.get_ip()
-      print "The external IP of your machine is '%s'" % ip
+      print("The external IP of your machine is '%s'" % ip)
   except moznetwork.NetworkError:
-      print "Unable to determine IP address of machine"
+      print("Unable to determine IP address of machine")
       raise
 
 """
 
-from moznetwork import get_ip
+from .moznetwork import get_ip
 
 __all__ = ['get_ip']
diff --git a/testing/mozbase/moznetwork/moznetwork/moznetwork.py b/testing/mozbase/moznetwork/moznetwork/moznetwork.py
index 5376496039..03b9cf15c3 100644
--- a/testing/mozbase/moznetwork/moznetwork/moznetwork.py
+++ b/testing/mozbase/moznetwork/moznetwork/moznetwork.py
@@ -51,7 +51,7 @@ def _get_interface_list():
                  socket.inet_ntoa(namestr[i + 20:i + 24]))
                 for i in range(0, outbytes, struct_size)]
 
-    except IOError:
+    except OSError:
         raise NetworkError('Unable to call ioctl with SIOCGIFCONF')
 
 
@@ -72,13 +72,13 @@ def _parse_ifconfig():
 
     # Attempt to determine the default interface in use.
     default_iface = _proc_matches(['route', '-n', 'get', 'default'],
-                                  'interface: (\w+)')
+                                  r'interface: (\w+)')
 
     if default_iface:
         addr_list = _proc_matches(['ifconfig', default_iface[0]],
-                                  'inet (\d+.\d+.\d+.\d+)')
+                                  r'inet (\d+.\d+.\d+.\d+)')
         if addr_list:
-            logger.debug('Default interface: [%s] %s' % (default_iface[0],
+            logger.debug('Default interface: [{}] {}'.format(default_iface[0],
                                                          addr_list[0]))
             if not addr_list[0].startswith('127.'):
                 return addr_list[0]
@@ -86,16 +86,16 @@ def _parse_ifconfig():
     # Iterate over plausible interfaces if we didn't find a suitable default.
     for iface in ['en%s' % i for i in range(10)]:
         addr_list = _proc_matches(['ifconfig', iface],
-                                  'inet (\d+.\d+.\d+.\d+)')
+                                  r'inet (\d+.\d+.\d+.\d+)')
         if addr_list:
-            logger.debug('Interface: [%s] %s' % (iface, addr_list[0]))
+            logger.debug('Interface: [{}] {}'.format(iface, addr_list[0]))
             if not addr_list[0].startswith('127.'):
                 return addr_list[0]
 
     # Just return any that isn't localhost. If we can't find one, we have
     # failed.
     addrs = _proc_matches(['ifconfig'],
-                          'inet (\d+.\d+.\d+.\d+)')
+                          r'inet (\d+.\d+.\d+.\d+)')
     try:
         return [addr for addr in addrs if not addr.startswith('127.')][0]
     except IndexError:
@@ -134,7 +134,7 @@ def get_ip():
         if mozinfo.isLinux:
             interfaces = _get_interface_list()
             for ifconfig in interfaces:
-                logger.debug('Interface: [%s] %s' % (ifconfig[0], ifconfig[1]))
+                logger.debug('Interface: [{}] {}'.format(ifconfig[0], ifconfig[1]))
                 if ifconfig[0] == 'lo':
                     continue
                 else:
diff --git a/testing/mozbase/moznetwork/tests/test.py b/testing/mozbase/moznetwork/tests/test.py
index 79eee6b038..e026010feb 100644
--- a/testing/mozbase/moznetwork/tests/test.py
+++ b/testing/mozbase/moznetwork/tests/test.py
@@ -4,7 +4,7 @@ Unit-Tests for moznetwork
 """
 
 import os
-import mock
+from unittest import mock
 import mozinfo
 import moznetwork
 import re
@@ -26,8 +26,8 @@ def verify_ip_in_list(ip):
 
     # Regex to match IPv4 addresses.
     # 0-255.0-255.0-255.0-255, note order is important here.
-    regexip = re.compile("((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}"
-                         "(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)")
+    regexip = re.compile(r"((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}"
+                         r"(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)")
 
     if mozinfo.isLinux or mozinfo.isMac or mozinfo.isBsd:
         # if "/sbin/ifconfig" exist, use it because it may not be in the
diff --git a/testing/mozbase/mozprocess/mozprocess/__init__.py b/testing/mozbase/mozprocess/mozprocess/__init__.py
index 0b238c2b25..fadb464639 100644
--- a/testing/mozbase/mozprocess/mozprocess/__init__.py
+++ b/testing/mozbase/mozprocess/mozprocess/__init__.py
@@ -3,6 +3,5 @@
 # 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
 
 from .processhandler import *
diff --git a/testing/mozbase/mozprocess/mozprocess/processhandler.py b/testing/mozbase/mozprocess/mozprocess/processhandler.py
index 661a7820e2..e80b59ac1e 100644
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -2,7 +2,6 @@
 # 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 os
 import signal
@@ -11,7 +10,7 @@ import sys
 import threading
 import time
 import traceback
-from Queue import Queue, Empty
+from queue import Queue, Empty
 from datetime import datetime
 
 __all__ = ['ProcessHandlerMixin', 'ProcessHandler', 'LogOutput',
@@ -112,7 +111,7 @@ class ProcessHandlerMixin(object):
                                           shell, cwd, env,
                                           universal_newlines, startupinfo, creationflags)
             except OSError:
-                print >> sys.stderr, args
+                print(args, file=sys.stderr)
                 raise
 
         def debug(self, msg):
@@ -121,14 +120,14 @@ class ProcessHandlerMixin(object):
             thread = threading.current_thread().name
             print("DBG::MOZPROC PID:{} ({}) | {}".format(self.pid, thread, msg))
 
-        def __del__(self, _maxint=sys.maxint):
+        def __del__(self, _maxint=sys.maxsize):
             if isWin:
                 handle = getattr(self, '_handle', None)
                 if handle:
                     if hasattr(self, '_internal_poll'):
                         self._internal_poll(_deadstate=_maxint)
                     else:
-                        self.poll(_deadstate=sys.maxint)
+                        self.poll(_deadstate=sys.maxsize)
                 if handle or self._job or self._io_port:
                     self._cleanup()
             else:
@@ -161,7 +160,7 @@ class ProcessHandlerMixin(object):
                             # application might already have been terminated itself. Any other
                             # error would indicate a problem in killing the process.
                             if getattr(e, "errno", None) != 3:
-                                print >> sys.stderr, "Could not terminate process: %s" % self.pid
+                                print("Could not terminate process: %s" % self.pid, file=sys.stderr)
                                 raise
                     else:
                         os.kill(pid, sig)
@@ -196,7 +195,7 @@ class ProcessHandlerMixin(object):
 
             return subprocess.Popen.poll(self)
 
-        def wait(self):
+        def wait(self, timeout=None):
             """ Popen.wait
                 Called to wait for a running process to shut down and return
                 its exit code
@@ -228,7 +227,7 @@ class ProcessHandlerMixin(object):
                      p2cread, p2cwrite,
                      c2pread, c2pwrite,
                      errread, errwrite) = args_tuple
-                if not isinstance(args, basestring):
+                if not isinstance(args, str):
                     args = subprocess.list2cmdline(args)
 
                 # Always or in the create new process group
@@ -256,8 +255,7 @@ class ProcessHandlerMixin(object):
                 if not (can_create_job or can_nest_jobs) and not self._ignore_children:
                     # We can't create job objects AND the user wanted us to
                     # Warn the user about this.
-                    print >> sys.stderr, \
-                        "ProcessManager UNABLE to use job objects to manage child processes"
+                    print("ProcessManager UNABLE to use job objects to manage child processes", file=sys.stderr)
 
                 # set process creation flags
                 creationflags |= winprocess.CREATE_SUSPENDED
@@ -267,7 +265,7 @@ class ProcessHandlerMixin(object):
                 if not (can_create_job or can_nest_jobs):
                     # Since we've warned, we just log info here to inform you
                     # of the consequence of setting ignore_children = True
-                    print "ProcessManager NOT managing child processes"
+                    print("ProcessManager NOT managing child processes")
 
                 # create the process
                 hp, ht, pid, tid = winprocess.CreateProcess(
@@ -340,10 +338,10 @@ class ProcessHandlerMixin(object):
                         # Spin up our thread for managing the IO Completion Port
                         self._procmgrthread = threading.Thread(target=self._procmgr)
                     except:
-                        print >> sys.stderr, """Exception trying to use job objects;
-falling back to not using job objects for managing child processes"""
+                        print("""Exception trying to use job objects;
+falling back to not using job objects for managing child processes""", file=sys.stderr)
                         tb = traceback.format_exc()
-                        print >> sys.stderr, tb
+                        print(tb, file=sys.stderr)
                         # Ensure no dangling handles left behind
                         self._cleanup_job_io_port()
                 else:
@@ -406,14 +404,10 @@ falling back to not using job objects for managing child processes"""
                         # don't want to mistake that situation for the situation of an unexpected
                         # parent abort (which is what we're looking for here).
                         if diff.seconds > self.MAX_IOCOMPLETION_PORT_NOTIFICATION_DELAY:
-                            print >> sys.stderr, \
-                                "WARNING | IO Completion Port failed to signal process shutdown"
-                            print >> sys.stderr, \
-                                "Parent process %s exited with children alive:" % self.pid
-                            print >> sys.stderr, \
-                                "PIDS: %s" % ', '.join([str(i) for i in self._spawned_procs])
-                            print >> sys.stderr, \
-                                "Attempting to kill them, but no guarantee of success"
+                            print("WARNING | IO Completion Port failed to signal process shutdown", file=sys.stderr)
+                            print("Parent process %s exited with children alive:" % self.pid, file=sys.stderr)
+                            print("PIDS: %s" % ', '.join([str(i) for i in self._spawned_procs]), file=sys.stderr)
+                            print("Attempting to kill them, but no guarantee of success", file=sys.stderr)
 
                             self.kill()
                             self._process_events.put({self.pid: 'FINISHED'})
@@ -424,16 +418,15 @@ falling back to not using job objects for managing child processes"""
                         errcode = winprocess.GetLastError()
                         if errcode == winprocess.ERROR_ABANDONED_WAIT_0:
                             # Then something has killed the port, break the loop
-                            print >> sys.stderr, "IO Completion Port unexpectedly closed"
+                            print("IO Completion Port unexpectedly closed", file=sys.stderr)
                             self._process_events.put({self.pid: 'FINISHED'})
                             break
                         elif errcode == winprocess.WAIT_TIMEOUT:
                             # Timeouts are expected, just keep on polling
                             continue
                         else:
-                            print >> sys.stderr, \
-                                "Error Code %s trying to query IO Completion Port, " \
-                                "exiting" % errcode
+                            print("Error Code %s trying to query IO Completion Port, "
+                                "exiting" % errcode, file=sys.stderr)
                             raise WinError(errcode)
                             break
 
@@ -480,7 +473,7 @@ falling back to not using job objects for managing child processes"""
                             self.debug("We got a message %s" % msgid.value)
                             pass
 
-            def _wait(self):
+            def _wait(self, timeout=None):
                 # First, check to see if the process is still running
                 if self._handle:
                     self.returncode = winprocess.GetExitCodeProcess(self._handle)
@@ -534,11 +527,11 @@ falling back to not using job objects for managing child processes"""
 
                     if rc == winprocess.WAIT_TIMEOUT:
                         # The process isn't dead, so kill it
-                        print "Timed out waiting for process to close, attempting TerminateProcess"
+                        print("Timed out waiting for process to close, attempting TerminateProcess")
                         self.kill()
                     elif rc == winprocess.WAIT_OBJECT_0:
                         # We caught WAIT_OBJECT_0, which indicates all is well
-                        print "Single process terminated successfully"
+                        print("Single process terminated successfully")
                         self.returncode = winprocess.GetExitCodeProcess(self._handle)
                     else:
                         # An error occured we should probably throw
@@ -589,7 +582,7 @@ falling back to not using job objects for managing child processes"""
 
         elif isPosix:
 
-            def _wait(self):
+            def _wait(self, timeout=None):
                 """ Haven't found any reason to differentiate between these platforms
                     so they all use the same wait callback.  If it is necessary to
                     craft different styles of wait, then a new _wait method
@@ -616,15 +609,23 @@ falling back to not using job objects for managing child processes"""
                         if getattr(e, "errno", None) != 10:
                             # Error 10 is "no child process", which could indicate normal
                             # close
-                            print >> sys.stderr, \
-                                "Encountered error waiting for pid to close: %s" % e
+                            print("Encountered error waiting for pid to close: %s" % e, file=sys.stderr)
                             raise
 
                         return self.returncode
 
                 else:
-                    # For non-group wait, call base class
-                    subprocess.Popen.wait(self)
+                    # For non-group wait, use os.waitpid directly to avoid
+                    # infinite recursion with Python 3.13's Popen.wait()
+                    if self.returncode is None:
+                        try:
+                            pid, sts = os.waitpid(self.pid, 0)
+                            if os.WIFSIGNALED(sts):
+                                self.returncode = -os.WTERMSIG(sts)
+                            elif os.WIFEXITED(sts):
+                                self.returncode = os.WEXITSTATUS(sts)
+                        except OSError:
+                            pass
                     return self.returncode
 
             def _cleanup(self):
@@ -632,11 +633,20 @@ falling back to not using job objects for managing child processes"""
 
         else:
             # An unrecognized platform, we will call the base class for everything
-            print >> sys.stderr, \
-                "Unrecognized platform, process groups may not be managed properly"
+            print("Unrecognized platform, process groups may not be managed properly", file=sys.stderr)
 
-            def _wait(self):
-                self.returncode = subprocess.Popen.wait(self)
+            def _wait(self, timeout=None):
+                # Use os.waitpid directly to avoid infinite recursion
+                # with Python 3.13's Popen.wait() which calls self._wait()
+                if self.returncode is None:
+                    try:
+                        pid, sts = os.waitpid(self.pid, 0)
+                        if os.WIFSIGNALED(sts):
+                            self.returncode = -os.WTERMSIG(sts)
+                        elif os.WIFEXITED(sts):
+                            self.returncode = os.WEXITSTATUS(sts)
+                    except OSError:
+                        pass
                 return self.returncode
 
             def _cleanup(self):
@@ -842,8 +852,8 @@ falling back to not using job objects for managing child processes"""
 
     # TODO Remove this method when consumers have been fixed
     def waitForFinish(self, timeout=None):
-        print >> sys.stderr, "MOZPROCESS WARNING: ProcessHandler.waitForFinish() is deprecated, " \
-                             "use ProcessHandler.wait() instead"
+        print("MOZPROCESS WARNING: ProcessHandler.waitForFinish() is deprecated, "
+            "use ProcessHandler.wait() instead", file=sys.stderr)
         return self.wait(timeout=timeout)
 
     @property
@@ -874,10 +884,9 @@ falling back to not using job objects for managing child processes"""
 
             if new_pgid and new_pgid != self.proc.pgid:
                 self.proc.detached_pid = new_pid
-                print >> sys.stdout, \
-                    'Child process with id "%s" has been marked as detached because it is no ' \
-                    'longer in the managed process group. Keeping reference to the process id ' \
-                    '"%s" which is the new child process.' % (self.pid, new_pid)
+                print('Child process with id "%s" has been marked as detached because it is no '
+                    'longer in the managed process group. Keeping reference to the process id '
+                    '"%s" which is the new child process.' % (self.pid, new_pid), file=sys.stdout)
 
 
 class CallableList(list):
@@ -966,14 +975,20 @@ class ProcessReader(object):
             else:
                 if output_timeout is not None:
                     output_timeout = now + self.output_timeout
-                callback(line.rstrip())
+                _l = line.rstrip()
+                if isinstance(_l, bytes):
+                    _l = _l.decode('utf-8', errors='replace')
+                callback(_l)
             if timeout is not None and now > timeout:
                 timed_out = True
                 break
         # process remaining lines to read
         while not queue.empty():
             line, callback = queue.get(False)
-            callback(line.rstrip())
+            _l = line.rstrip()
+            if isinstance(_l, bytes):
+                _l = _l.decode('utf-8', errors='replace')
+            callback(_l)
         if timed_out:
             self.timeout_callback()
         if stdout_reader:
diff --git a/testing/mozbase/mozprocess/mozprocess/qijo.py b/testing/mozbase/mozprocess/mozprocess/qijo.py
index ce23909fa5..2b006b1183 100644
--- a/testing/mozbase/mozprocess/mozprocess/qijo.py
+++ b/testing/mozbase/mozprocess/mozprocess/qijo.py
@@ -2,7 +2,6 @@
 # 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
 
 from ctypes import (
     c_void_p,
@@ -87,7 +86,7 @@ JobObjectBasicAndIoAccountingInformation = 8
 JobObjectExtendedLimitInformation = 9
 
 
-class JobObjectInfo(object):
+class JobObjectInfo:
     mapping = {'JobObjectBasicAndIoAccountingInformation': 8,
                'JobObjectExtendedLimitInformation': 9,
                'JobObjectAssociateCompletionPortInformation': 7}
@@ -98,12 +97,12 @@ class JobObjectInfo(object):
     }
 
     def __init__(self, _class):
-        if isinstance(_class, basestring):
+        if isinstance(_class, str):
             assert _class in self.mapping, \
-                'Class should be one of %s; you gave %s' % (self.mapping, _class)
+                'Class should be one of {}; you gave {}'.format(self.mapping, _class)
             _class = self.mapping[_class]
         assert _class in self.structures, \
-            'Class should be one of %s; you gave %s' % (self.structures, _class)
+            'Class should be one of {}; you gave {}'.format(self.structures, _class)
         self.code = _class
         self.info = self.structures[_class]()
 
@@ -131,7 +130,7 @@ _QueryInformationJobObject = QueryInformationJobObjectProto(
 )
 
 
-class SubscriptableReadOnlyStruct(object):
+class SubscriptableReadOnlyStruct:
 
     def __init__(self, struct):
         self._struct = struct
diff --git a/testing/mozbase/mozprocess/mozprocess/winprocess.py b/testing/mozbase/mozprocess/mozprocess/winprocess.py
index b748f8f302..50de744463 100644
--- a/testing/mozbase/mozprocess/mozprocess/winprocess.py
+++ b/testing/mozbase/mozprocess/mozprocess/winprocess.py
@@ -447,33 +447,33 @@ def CanCreateJobObject():
 
 
 def parent():
-    print 'Starting parent'
+    print('Starting parent')
     currentProc = GetCurrentProcess()
     if IsProcessInJob(currentProc):
-        print >> sys.stderr, "You should not be in a job object to test"
+        print("You should not be in a job object to test", file=sys.stderr)
         sys.exit(1)
     assert CanCreateJobObject()
-    print 'File: %s' % __file__
+    print('File: %s' % __file__)
     command = [sys.executable, __file__, '-child']
-    print 'Running command: %s' % command
+    print('Running command: %s' % command)
     process = subprocess.Popen(command)
     process.kill()
     code = process.returncode
-    print 'Child code: %s' % code
+    print('Child code: %s' % code)
     assert code == 127
 
 
 def child():
-    print 'Starting child'
+    print('Starting child')
     currentProc = GetCurrentProcess()
     injob = IsProcessInJob(currentProc)
-    print "Is in a job?: %s" % injob
+    print("Is in a job?: %s" % injob)
     can_create = CanCreateJobObject()
-    print 'Can create job?: %s' % can_create
+    print('Can create job?: %s' % can_create)
     process = subprocess.Popen('c:\\windows\\notepad.exe')
     assert process._job
     jobinfo = QueryInformationJobObject(process._job, 'JobObjectExtendedLimitInformation')
-    print 'Job info: %s' % jobinfo
+    print('Job info: %s' % jobinfo)
     limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
-    print 'LimitFlags: %s' % limitflags
+    print('LimitFlags: %s' % limitflags)
     process.kill()
diff --git a/testing/mozbase/mozprocess/tests/proccountfive.py b/testing/mozbase/mozprocess/tests/proccountfive.py
index 5ec74b32ab..c2c5b0751c 100644
--- a/testing/mozbase/mozprocess/tests/proccountfive.py
+++ b/testing/mozbase/mozprocess/tests/proccountfive.py
@@ -1,2 +1,3 @@
+from __future__ import print_function
 for i in range(0, 5):
-    print i
+    print(i)
diff --git a/testing/mozbase/mozprocess/tests/proclaunch.py b/testing/mozbase/mozprocess/tests/proclaunch.py
index ad06a23a16..926440b22f 100644
--- a/testing/mozbase/mozprocess/tests/proclaunch.py
+++ b/testing/mozbase/mozprocess/tests/proclaunch.py
@@ -159,7 +159,7 @@ class ProcessLauncher(object):
 
         maxtime = self.children[proc_name].maxtime
         if self.verbose:
-            print "%sLaunching %s for %d*%d seconds" % (" " * level,
+            print("%sLaunching %s for %d*%d seconds" % (" " * level,)
                                                         proc_name,
                                                         maxtime,
                                                         self.UNIT_TIME)
@@ -174,7 +174,7 @@ class ProcessLauncher(object):
 
         self._launch(maxtime)
         if self.verbose:
-            print "%sFinished %s" % (" " * level, proc_name)
+            print("%sFinished %s" % (" " * level, proc_name))
 
     def _launch(self, running_time):
         """
diff --git a/testing/mozbase/mozprocess/tests/procnonewline.py b/testing/mozbase/mozprocess/tests/procnonewline.py
index 428a02bcb5..75a7a00ed7 100644
--- a/testing/mozbase/mozprocess/tests/procnonewline.py
+++ b/testing/mozbase/mozprocess/tests/procnonewline.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import sys
-print "this is a newline"
+print("this is a newline")
 sys.stdout.write("this has NO newline")
diff --git a/testing/mozbase/mozprocess/tests/test_mozprocess.py b/testing/mozbase/mozprocess/tests/test_mozprocess.py
index bf8ba194c2..eb80c69b81 100644
--- a/testing/mozbase/mozprocess/tests/test_mozprocess.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import os
 import subprocess
 import sys
@@ -42,9 +43,9 @@ def make_proclaunch(aDir):
         stdout, stderr = process.communicate()
         if process.returncode:
             # SomethingBadHappen; print all the things
-            print "%s: exit %d" % (command, process.returncode)
-            print "stdout:\n%s" % stdout
-            print "stderr:\n%s" % stderr
+            print(("%s: exit %d" % (command, process.returncode)))
+            print(("stdout:\n%s" % stdout))
+            print(("stderr:\n%s" % stderr))
             raise subprocess.CalledProcessError(process.returncode, command, stdout)
 
     # ensure the launcher now exists
@@ -110,7 +111,7 @@ class ProcTest(proctest.ProcTest):
             processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
                                           args=["1", "2", "3"],
                                           cwd=here)
-        except TypeError, e:
+        except TypeError as e:
             err = e
 
         self.assertTrue(err)
@@ -128,7 +129,7 @@ class ProcTest(proctest.ProcTest):
             processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
                                           args=["1", "2", "3"],
                                           cwd=here)
-        except TypeError, e:
+        except TypeError as e:
             err = e
 
         self.assertTrue(err)
diff --git a/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py b/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
index 36dbc95cc5..cd0c0c2173 100644
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
@@ -74,7 +74,7 @@ class ProcTestKill(proctest.ProcTest):
         p.run()
         p.kill()
 
-        self.assertEquals(p.proc.returncode, -signal.SIGTERM)
+        self.assertEqual(p.proc.returncode, -signal.SIGTERM)
 
     @unittest.skipUnless(processhandler.isPosix, "posix only")
     def test_process_kill_with_sigint_if_needed(self):
@@ -85,7 +85,7 @@ class ProcTestKill(proctest.ProcTest):
         time.sleep(1)
         p.kill()
 
-        self.assertEquals(p.proc.returncode, -signal.SIGKILL)
+        self.assertEqual(p.proc.returncode, -signal.SIGKILL)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py b/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
index 7a7c690d13..d375836610 100644
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
@@ -1,5 +1,4 @@
 #!/usr/bin/env python
-# -*- coding: utf-8 -*-
 
 import os
 import unittest
diff --git a/testing/mozbase/mozprocess/tests/test_mozprocess_output.py b/testing/mozbase/mozprocess/tests/test_mozprocess_output.py
index e9ad266209..107bbbef87 100644
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_output.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_output.py
@@ -44,7 +44,7 @@ class ProcTestOutput(proctest.ProcTest):
             stream.write(str(i) + '\n')
 
         buf.flush()
-        self.assertEquals(stream.getvalue().strip(), expected)
+        self.assertEqual(stream.getvalue().strip(), expected)
 
         # make sure mozprocess doesn't close the stream
         # since mozprocess didn't create it
diff --git a/testing/mozbase/mozprocess/tests/test_mozprocess_params.py b/testing/mozbase/mozprocess/tests/test_mozprocess_params.py
index d4d1f00f36..6c1cf1daef 100644
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_params.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_params.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import unittest
 from mozprocess import processhandler
 
@@ -13,7 +14,7 @@ class ParamTests(unittest.TestCase):
     def test_process_outputline_handler(self):
         """Parameter processOutputLine is accepted with a single function"""
         def output(line):
-            print("output " + str(line))
+            print(("output " + str(line)))
         err = None
         try:
             processhandler.ProcessHandler(['ls', '-l'], processOutputLine=output)
@@ -24,7 +25,7 @@ class ParamTests(unittest.TestCase):
     def test_process_outputline_handler_list(self):
         """Parameter processOutputLine is accepted with a list of functions"""
         def output(line):
-            print("output " + str(line))
+            print(("output " + str(line)))
         err = None
         try:
             processhandler.ProcessHandler(['ls', '-l'], processOutputLine=[output])
diff --git a/testing/mozbase/mozprofile/mozprofile/__init__.py b/testing/mozbase/mozprofile/mozprofile/__init__.py
index 96bf1020bc..7416820652 100644
--- a/testing/mozbase/mozprofile/mozprofile/__init__.py
+++ b/testing/mozbase/mozprofile/mozprofile/__init__.py
@@ -11,11 +11,11 @@ subclasses ``FirefoxProfile`` and ``ThundebirdProfile`` are available
 with preset preferences for those applications.
 """
 
-from addons import *
-from cli import *
-from diff import *
-from permissions import *
-from prefs import *
-from profile import *
-from view import *
-from webapps import *
+from .addons import *
+from .cli import *
+from .diff import *
+from .permissions import *
+from .prefs import *
+from .profile import *
+from .view import *
+from .webapps import *
diff --git a/testing/mozbase/mozprofile/mozprofile/addons.py b/testing/mozbase/mozprofile/mozprofile/addons.py
index e96fd6b36c..4122579f04 100644
--- a/testing/mozbase/mozprofile/mozprofile/addons.py
+++ b/testing/mozbase/mozprofile/mozprofile/addons.py
@@ -6,12 +6,13 @@ import os
 import shutil
 import sys
 import tempfile
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import zipfile
 from xml.dom import minidom
 
 import mozfile
 from mozlog.unstructured import getLogger
+import six
 
 # Needed for the AMO's rest API -
 # https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API
@@ -104,7 +105,7 @@ class AddonManager(object):
         :param target_folder: Folder to store the XPI file in
 
         """
-        response = urllib2.urlopen(url)
+        response = six.moves.urllib.request.urlopen(url)
         fd, path = tempfile.mkstemp(suffix='.xpi')
         os.write(fd, response.read())
         os.close(fd)
@@ -168,14 +169,14 @@ class AddonManager(object):
 
         # install addon paths
         if addons:
-            if isinstance(addons, basestring):
+            if isinstance(addons, str):
                 addons = [addons]
             for addon in set(addons):
                 self.install_from_path(addon)
 
         # install addon manifests
         if manifests:
-            if isinstance(manifests, basestring):
+            if isinstance(manifests, str):
                 manifests = [manifests]
             for manifest in manifests:
                 self.install_from_manifest(manifest)
@@ -226,7 +227,7 @@ class AddonManager(object):
 
         .. _query-documentation: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API # noqa
         """
-        response = urllib2.urlopen(query)
+        response = six.moves.urllib.request.urlopen(query)
         dom = minidom.parseString(response.read())
         for node in dom.getElementsByTagName('install')[0].childNodes:
             if node.nodeType == node.TEXT_NODE:
@@ -291,7 +292,7 @@ class AddonManager(object):
             else:
                 raise IOError('Add-on path is neither an XPI nor a directory: %s' % addon_path)
         except (IOError, KeyError) as e:
-            raise AddonFormatError(str(e)), None, sys.exc_info()[2]
+            six.reraise(AddonFormatError(str(e)), None, sys.exc_info()[2])
 
         try:
             doc = minidom.parseString(manifest)
@@ -304,18 +305,18 @@ class AddonManager(object):
             for entry, value in description.attributes.items():
                 # Remove the namespace prefix from the tag for comparison
                 entry = entry.replace(em, "")
-                if entry in details.keys():
+                if entry in list(details.keys()):
                     details.update({entry: value})
             for node in description.childNodes:
                 # Remove the namespace prefix from the tag for comparison
                 entry = node.nodeName.replace(em, "")
-                if entry in details.keys():
+                if entry in list(details.keys()):
                     details.update({entry: get_text(node)})
         except Exception as e:
-            raise AddonFormatError(str(e)), None, sys.exc_info()[2]
+            six.reraise(AddonFormatError(str(e)), None, sys.exc_info()[2])
 
         # turn unpack into a true/false value
-        if isinstance(details['unpack'], basestring):
+        if isinstance(details['unpack'], str):
             details['unpack'] = details['unpack'].lower() == 'true'
 
         # If no ID is set, the add-on is invalid
diff --git a/testing/mozbase/mozprofile/mozprofile/cli.py b/testing/mozbase/mozprofile/mozprofile/cli.py
index 1dd513e561..5b265241b8 100755
--- a/testing/mozbase/mozprofile/mozprofile/cli.py
+++ b/testing/mozbase/mozprofile/mozprofile/cli.py
@@ -11,11 +11,12 @@ If no profile is specified, a new profile is created and the path of the
 resulting profile is printed.
 """
 
+from __future__ import print_function
 import sys
 from optparse import OptionParser
-from prefs import Preferences
-from profile import FirefoxProfile
-from profile import Profile
+from .prefs import Preferences
+from .profile import FirefoxProfile
+from .profile import Profile
 
 __all__ = ['MozProfileCLI', 'cli']
 
@@ -120,12 +121,12 @@ def cli(args=sys.argv[1:]):
 
     if cli.options.view:
         # view the profile, if specified
-        print profile.summary()
+        print(profile.summary())
         return
 
     # if no profile was passed in print the newly created profile
     if not cli.options.profile:
-        print profile.profile
+        print(profile.profile)
 
 if __name__ == '__main__':
     cli()
diff --git a/testing/mozbase/mozprofile/mozprofile/diff.py b/testing/mozbase/mozprofile/mozprofile/diff.py
index 98776e838c..c2fb0ef88e 100644
--- a/testing/mozbase/mozprofile/mozprofile/diff.py
+++ b/testing/mozbase/mozprofile/mozprofile/diff.py
@@ -4,8 +4,9 @@
 diff two profile summaries
 """
 
+from __future__ import print_function
 import difflib
-import profile
+from . import profile
 import optparse
 import os
 import sys
@@ -72,10 +73,10 @@ def diff_profiles(args=sys.argv[1:]):
     # display them
     while diffs:
         key, value = diffs.pop(0)
-        print '[%s]:\n' % key
-        print value
+        print('[%s]:\n' % key)
+        print(value)
         if diffs:
-            print '-' * 4
+            print('-' * 4)
 
 if __name__ == '__main__':
     diff_profiles()
diff --git a/testing/mozbase/mozprofile/mozprofile/permissions.py b/testing/mozbase/mozprofile/mozprofile/permissions.py
index ea13d96f02..b9e7769637 100644
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py
+++ b/testing/mozbase/mozprofile/mozprofile/permissions.py
@@ -10,7 +10,8 @@ add permissions to the profile
 import codecs
 import os
 import sqlite3
-import urlparse
+import six.moves.urllib.parse
+import six
 
 __all__ = ['MissingPrimaryLocationError', 'MultiplePrimaryLocationsError',
            'DEFAULT_PORTS', 'DuplicateLocationError', 'BadPortLocationError',
@@ -78,7 +79,7 @@ class LocationsSyntaxError(Exception):
         return s
 
 
-class Location(object):
+class Location:
     """Represents a location line in server-locations.txt."""
 
     attrs = ('scheme', 'host', 'port')
@@ -100,13 +101,13 @@ class Location(object):
     __eq__ = isEqual
 
     def url(self):
-        return '%s://%s:%s' % (self.scheme, self.host, self.port)
+        return '{}://{}:{}'.format(self.scheme, self.host, self.port)
 
     def __str__(self):
-        return '%s  %s' % (self.url(), ','.join(self.options))
+        return '{}  {}'.format(self.url(), ','.join(self.options))
 
 
-class ServerLocations(object):
+class ServerLocations:
     """Iterable collection of locations.
     Use provided functions to add new locations, rather that manipulating
     _locations directly, in order to check for errors and to ensure the
@@ -137,7 +138,7 @@ class ServerLocations(object):
             self.add_callback([location])
 
     def add_host(self, host, port='80', scheme='http', options='privileged'):
-        if isinstance(options, basestring):
+        if isinstance(options, str):
             options = options.split(',')
         self.add(Location(scheme, host, port, options))
 
@@ -180,7 +181,7 @@ class ServerLocations(object):
             # parse the server url
             if '://' not in server:
                 server = 'http://' + server
-            scheme, netloc, path, query, fragment = urlparse.urlsplit(server)
+            scheme, netloc, path, query, fragment = six.moves.urllib.parse.urlsplit(server)
             # get the host and port
             try:
                 host, port = netloc.rsplit(':', 1)
@@ -205,7 +206,7 @@ class ServerLocations(object):
             self.add_callback(new_locations)
 
 
-class Permissions(object):
+class Permissions:
     """Allows handling of permissions for ``mozprofile``"""
 
     def __init__(self, profileDir, locations=None):
@@ -267,7 +268,7 @@ class Permissions(object):
         for location in locations:
             # set the permissions
             permissions = {'allowXULXBL': 'noxul' not in location.options}
-            for perm, allow in permissions.iteritems():
+            for perm, allow in permissions.items():
                 if allow:
                     permission_type = 1
                 else:
diff --git a/testing/mozbase/mozprofile/mozprofile/prefs.py b/testing/mozbase/mozprofile/mozprofile/prefs.py
index b0eb01e280..4b0cc9c251 100644
--- a/testing/mozbase/mozprofile/mozprofile/prefs.py
+++ b/testing/mozbase/mozprofile/mozprofile/prefs.py
@@ -6,11 +6,12 @@
 user preferences
 """
 
+from __future__ import print_function
 import json
 import mozfile
 import os
 import tokenize
-from ConfigParser import SafeConfigParser as ConfigParser
+from configparser import ConfigParser
 from StringIO import StringIO
 
 __all__ = ('PreferencesReadError', 'Preferences')
@@ -35,7 +36,7 @@ class Preferences(object):
         """
         # wants a list of 2-tuples
         if isinstance(prefs, dict):
-            prefs = prefs.items()
+            prefs = list(prefs.items())
         if cast:
             prefs = [(i, self.cast(j)) for i, j in prefs]
         self._prefs += prefs
@@ -63,7 +64,7 @@ class Preferences(object):
           with the ''s removed from both sides
         """
 
-        if not isinstance(value, basestring):
+        if not isinstance(value, str):
             return value  # no op
         quote = "'"
         if value == 'true':
@@ -124,7 +125,7 @@ class Preferences(object):
                 raise PreferencesReadError("No section '%s' in %s" % (section, path))
             retval = parser.items(section, raw=True)
         else:
-            retval = parser.defaults().items()
+            retval = list(parser.defaults().items())
 
         # cast the preferences since .ini is just strings
         return [(i, cls.cast(j)) for i, j in retval]
@@ -142,10 +143,10 @@ class Preferences(object):
                 raise PreferencesReadError("Malformed preferences: %s" % path)
             values = [i[1] for i in prefs]
         elif isinstance(prefs, dict):
-            values = prefs.values()
+            values = list(prefs.values())
         else:
             raise PreferencesReadError("Malformed preferences: %s" % path)
-        types = (bool, basestring, int)
+        types = (bool, str, int)
         if [i for i in values if not [isinstance(i, j) for j in types]]:
             raise PreferencesReadError("Only bool, string, and int values allowed")
         return prefs
@@ -185,7 +186,7 @@ class Preferences(object):
         retval = []
 
         def pref(a, b):
-            if interpolation and isinstance(b, basestring):
+            if interpolation and isinstance(b, str):
                 b = b.format(**interpolation)
             retval.append((a, b))
         lines = [i.strip().rstrip(';') for i in string.split('\n') if i.strip()]
@@ -196,12 +197,12 @@ class Preferences(object):
             try:
                 eval(line, _globals, {})
             except SyntaxError:
-                print line
+                print(line)
                 raise
 
         # de-magic the marker
         for index, (key, value) in enumerate(retval):
-            if isinstance(value, basestring) and marker in value:
+            if isinstance(value, str) and marker in value:
                 retval[index] = (key, value.replace(marker, '//'))
 
         return retval
@@ -210,14 +211,14 @@ class Preferences(object):
     def write(cls, _file, prefs, pref_string='user_pref(%s, %s);'):
         """write preferences to a file"""
 
-        if isinstance(_file, basestring):
-            f = file(_file, 'a')
+        if isinstance(_file, str):
+            f = open(_file, 'a')
         else:
             f = _file
 
         if isinstance(prefs, dict):
             # order doesn't matter
-            prefs = prefs.items()
+            prefs = list(prefs.items())
 
         # serialize -> JSON
         _prefs = [(json.dumps(k), json.dumps(v))
@@ -225,8 +226,8 @@ class Preferences(object):
 
         # write the preferences
         for _pref in _prefs:
-            print >> f, pref_string % _pref
+            print(pref_string % _pref, file=f)
 
         # close the file if opened internally
-        if isinstance(_file, basestring):
+        if isinstance(_file, str):
             f.close()
diff --git a/testing/mozbase/mozprofile/mozprofile/profile.py b/testing/mozbase/mozprofile/mozprofile/profile.py
index b07b114492..21c75f5dc0 100644
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -7,12 +7,12 @@ import time
 import tempfile
 import uuid
 
-from addons import AddonManager
+from .addons import AddonManager
 import mozfile
-from permissions import Permissions
-from prefs import Preferences
+from .permissions import Permissions
+from .prefs import Preferences
 from shutil import copytree
-from webapps import WebappCollection
+from .webapps import WebappCollection
 
 __all__ = ['Profile',
            'FirefoxProfile',
@@ -20,7 +20,7 @@ __all__ = ['Profile',
            'ThunderbirdProfile']
 
 
-class Profile(object):
+class Profile:
     """Handles all operations regarding profile.
 
     Creating new profiles, installing add-ons, setting preferences and
@@ -30,7 +30,7 @@ class Profile(object):
     the object is garbage collected: ::
 
       profile = Profile()
-      print profile.profile  # this is the path to the created profile
+      print(profile.profile)  # this is the path to the created profile
       del profile
       # the profile path has been removed from disk
 
@@ -66,7 +66,7 @@ class Profile(object):
         if preferences:
             if isinstance(preferences, dict):
                 # unordered
-                preferences = preferences.items()
+                preferences = list(preferences.items())
 
             # sanity check
             assert not [i for i in preferences if len(i) != 2]
@@ -97,7 +97,7 @@ class Profile(object):
         self.written_prefs = set()
 
         # Our magic markers
-        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
+        nonce = '{} {}'.format(str(time.time()), uuid.uuid4())
         self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                            '#MozRunner Prefs End %s' % nonce)
 
@@ -220,7 +220,7 @@ class Profile(object):
 
         # this is a dict sometimes, convert
         if isinstance(preferences, dict):
-            preferences = preferences.items()
+            preferences = list(preferences.items())
 
         # add new prefs to preserve them during reset
         for new_pref in preferences:
@@ -238,7 +238,7 @@ class Profile(object):
         """
 
         path = os.path.join(self.profile, filename)
-        with file(path) as f:
+        with open(path) as f:
             lines = f.read().splitlines()
 
         def last_index(_list, value):
@@ -246,7 +246,7 @@ class Profile(object):
             returns the last index of an item;
             this should actually be part of python code but it isn't
             """
-            for index in reversed(range(len(_list))):
+            for index in reversed(list(range(len(_list)))):
                 if _list[index] == value:
                     return index
         s = last_index(lines, self.delimeters[0])
@@ -254,18 +254,18 @@ class Profile(object):
 
         # ensure both markers are found
         if s is None:
-            assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0])
+            assert e is None, '{} found without {}'.format(self.delimeters[1], self.delimeters[0])
             return False  # no preferences found
         elif e is None:
-            assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])
+            assert s is None, '{} found without {}'.format(self.delimeters[0], self.delimeters[1])
 
         # ensure the markers are in the proper order
-        assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e,
+        assert e > s, '{} found at {}, while {} found at {}'.format(self.delimeters[1], e,
                                                                 self.delimeters[0], s)
 
         # write the prefs
         cleaned_prefs = '\n'.join(lines[:s] + lines[e + 1:])
-        with file(path, 'w') as f:
+        with open(path, 'w') as f:
             f.write(cleaned_prefs)
         return True
 
@@ -311,7 +311,7 @@ class Profile(object):
                     prefs = dict(prefs)
                     parts.append((prefs_file,
                                   '\n%s' % ('\n'.join(
-                                      ['%s: %s' % (key, format_value(key, prefs[key]))
+                                      ['{}: {}'.format(key, format_value(key, prefs[key]))
                                        for key in sorted(prefs.keys())]))))
 
                     # Currently hardcorded to 'network.proxy.autoconfig_url'
@@ -340,7 +340,7 @@ class Profile(object):
         if return_parts:
             return parts
 
-        retval = '%s\n' % ('\n\n'.join(['[%s]: %s' % (key, value)
+        retval = '%s\n' % ('\n\n'.join(['[{}]: {}'.format(key, value)
                                         for key, value in parts]))
         return retval
 
diff --git a/testing/mozbase/mozprofile/mozprofile/view.py b/testing/mozbase/mozprofile/mozprofile/view.py
index fcab85b0a8..fb427b510d 100644
--- a/testing/mozbase/mozprofile/mozprofile/view.py
+++ b/testing/mozbase/mozprofile/mozprofile/view.py
@@ -4,6 +4,7 @@
 script to view mozilla profiles
 """
 
+from __future__ import print_function
 import mozprofile
 import optparse
 import os
@@ -35,9 +36,9 @@ def view_profile(args=sys.argv[1:]):
     while args:
         path = args.pop(0)
         profile = mozprofile.Profile(path)
-        print profile.summary()
+        print(profile.summary())
         if args:
-            print '-' * 4
+            print('-' * 4)
 
 if __name__ == '__main__':
     view_profile()
diff --git a/testing/mozbase/mozprofile/mozprofile/webapps.py b/testing/mozbase/mozprofile/mozprofile/webapps.py
index 4daf9ef06a..a9837f79e1 100644
--- a/testing/mozbase/mozprofile/mozprofile/webapps.py
+++ b/testing/mozbase/mozprofile/mozprofile/webapps.py
@@ -63,7 +63,7 @@ class Webapp(dict):
                 raise WebappFormatException("Webapp object missing required key '%s'" % key)
 
 
-class WebappCollection(object):
+class WebappCollection:
     """A list-like object that collects webapps and updates the webapp manifests"""
 
     json_template = Template(""""$name": {
@@ -110,7 +110,7 @@ class WebappCollection(object):
         :param json_template: [optional] string template describing the webapp json format
         :param manifest_template: [optional] string template describing the webapp manifest format
         """
-        if not isinstance(profile, basestring):
+        if not isinstance(profile, str):
             raise TypeError("Must provide path to a profile, received '%s'" % type(profile))
         self.profile = profile
         self.webapps_dir = os.path.join(self.profile, 'webapps')
@@ -123,7 +123,7 @@ class WebappCollection(object):
                 apps = [apps]
 
             for app in apps:
-                if isinstance(app, basestring) and os.path.isfile(app):
+                if isinstance(app, str) and os.path.isfile(app):
                     self.extend(self.read_json(app))
                 else:
                     self.append(app)
@@ -259,13 +259,13 @@ class WebappCollection(object):
 
         Returns a list of Webapp objects
         """
-        f = open(path, 'r')
+        f = open(path)
         app_json = json.load(f)
         f.close()
 
         apps = []
         if isinstance(app_json, dict):
-            for k, v in app_json.iteritems():
+            for k, v in app_json.items():
                 v['name'] = k
                 apps.append(v)
         else:
diff --git a/testing/mozbase/mozprofile/tests/addon_stubs.py b/testing/mozbase/mozprofile/tests/addon_stubs.py
index f9602de462..9675e314d8 100644
--- a/testing/mozbase/mozprofile/tests/addon_stubs.py
+++ b/testing/mozbase/mozprofile/tests/addon_stubs.py
@@ -34,23 +34,23 @@ def generate_addon(addon_id, path=None, name=None, xpi=True):
     Returns the file-path of the addon's .xpi file
     """
 
-    if addon_id not in stubs.keys():
-        raise IOError('Requested addon stub "%s" does not exist' % addon_id)
+    if addon_id not in list(stubs.keys()):
+        raise OSError('Requested addon stub "%s" does not exist' % addon_id)
 
     # Generate directory structure for addon
     try:
         tmpdir = path or tempfile.mkdtemp()
         addon_dir = os.path.join(tmpdir, name or addon_id)
         os.mkdir(addon_dir)
-    except IOError:
-        raise IOError('Could not generate directory structure for addon stub.')
+    except OSError:
+        raise OSError('Could not generate directory structure for addon stub.')
 
     # Write install.rdf for addon
     if stubs[addon_id]:
         install_rdf = os.path.join(addon_dir, 'install.rdf')
         with open(install_rdf, 'w') as f:
             manifest = os.path.join(here, 'install_manifests', stubs[addon_id])
-            f.write(open(manifest, 'r').read())
+            f.write(open(manifest).read())
 
     if not xpi:
         return addon_dir
diff --git a/testing/mozbase/mozprofile/tests/server_locations.py b/testing/mozbase/mozprofile/tests/server_locations.py
index 5aa5c0f5eb..6ab58879d1 100644
--- a/testing/mozbase/mozprofile/tests/server_locations.py
+++ b/testing/mozbase/mozprofile/tests/server_locations.py
@@ -60,21 +60,21 @@ http://example.org:80           privileged
         # ensure that they're what we expect
         self.assertEqual(len(locations), 6)
         i = iter(locations)
-        self.compare_location(i.next(), 'http', 'mochi.test', '8888',
+        self.compare_location(next(i), 'http', 'mochi.test', '8888',
                               ['primary', 'privileged'])
-        self.compare_location(i.next(), 'http', '127.0.0.1', '80',
+        self.compare_location(next(i), 'http', '127.0.0.1', '80',
                               ['privileged'])
-        self.compare_location(i.next(), 'http', '127.0.0.1', '8888',
+        self.compare_location(next(i), 'http', '127.0.0.1', '8888',
                               ['privileged'])
-        self.compare_location(i.next(), 'https', 'test', '80', ['privileged'])
-        self.compare_location(i.next(), 'http', 'example.org', '80',
+        self.compare_location(next(i), 'https', 'test', '80', ['privileged'])
+        self.compare_location(next(i), 'http', 'example.org', '80',
                               ['privileged'])
-        self.compare_location(i.next(), 'http', 'test1.example.org', '8888',
+        self.compare_location(next(i), 'http', 'test1.example.org', '8888',
                               ['privileged'])
 
         locations.add_host('mozilla.org')
         self.assertEqual(len(locations), 7)
-        self.compare_location(i.next(), 'http', 'mozilla.org', '80',
+        self.compare_location(next(i), 'http', 'mozilla.org', '80',
                               ['privileged'])
 
         # test some errors
@@ -116,7 +116,7 @@ http://example.org:80           privileged
         self.assertEqual(exc.lineno, 4)
 
     def test_server_locations_callback(self):
-        class CallbackTest(object):
+        class CallbackTest:
             last_locations = None
 
             def callback(self, locations):
diff --git a/testing/mozbase/mozprofile/tests/test_addons.py b/testing/mozbase/mozprofile/tests/test_addons.py
index 93b930feac..171c6ce497 100644
--- a/testing/mozbase/mozprofile/tests/test_addons.py
+++ b/testing/mozbase/mozprofile/tests/test_addons.py
@@ -8,7 +8,7 @@ import os
 import shutil
 import tempfile
 import unittest
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
 from manifestparser import ManifestParser
 import mozfile
@@ -17,6 +17,7 @@ import mozlog.unstructured as mozlog
 import mozprofile
 
 from addon_stubs import generate_addon, generate_manifest
+import six
 
 
 here = os.path.dirname(os.path.abspath(__file__))
@@ -99,7 +100,7 @@ class TestAddonsManager(unittest.TestCase):
 
         # Download from an invalid URL
         addon = server.get_url() + 'not_existent.xpi'
-        self.assertRaises(urllib2.HTTPError,
+        self.assertRaises(six.moves.urllib.error.HTTPError,
                           self.am.download, addon, self.tmpdir)
         self.assertEqual(os.listdir(self.tmpdir), [])
 
@@ -122,7 +123,7 @@ class TestAddonsManager(unittest.TestCase):
             self.am.install_from_path(temp_addon)
 
         # Generate a list of addons installed in the profile
-        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_installed = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
         self.assertEqual(addons_to_install.sort(), addons_installed.sort())
 
@@ -287,7 +288,7 @@ class TestAddonsManager(unittest.TestCase):
 
         self.am.install_from_manifest(temp_manifest)
         # Generate a list of addons installed in the profile
-        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_installed = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
         self.assertEqual(addons_installed.sort(), addons_to_install.sort())
 
@@ -327,7 +328,7 @@ class TestAddonsManager(unittest.TestCase):
         addon_two = generate_addon('test-addon-2@mozilla.org')
 
         self.am.install_addons(addon_one)
-        installed_addons = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        installed_addons = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
 
         # Create a new profile based on an existing profile
@@ -337,7 +338,7 @@ class TestAddonsManager(unittest.TestCase):
                                                        addons=addon_two)
         duplicate_profile.addon_manager.clean()
 
-        addons_after_cleanup = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_after_cleanup = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                                 duplicate_profile.profile, 'extensions', 'staged'))]
         # New addons installed should be removed by clean_addons()
         self.assertEqual(installed_addons, addons_after_cleanup)
diff --git a/testing/mozbase/mozprofile/tests/test_preferences.py b/testing/mozbase/mozprofile/tests/test_preferences.py
index 45d99c2e27..9ff9fc62dc 100755
--- a/testing/mozbase/mozprofile/tests/test_preferences.py
+++ b/testing/mozbase/mozprofile/tests/test_preferences.py
@@ -62,9 +62,9 @@ class PreferencesTest(unittest.TestCase):
 
         _prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"}
         commandline = []
-        _prefs = _prefs.items()
+        _prefs = list(_prefs.items())
         for pref, value in _prefs:
-            commandline += ["--pref", "%s:%s" % (pref, value)]
+            commandline += ["--pref", "{}:{}".format(pref, value)]
         self.compare_generated(_prefs, commandline)
 
     def test_ordered_prefs(self):
@@ -75,7 +75,7 @@ class PreferencesTest(unittest.TestCase):
                   ("webgl.verbose", 'false')]
         commandline = []
         for pref, value in _prefs:
-            commandline += ["--pref", "%s:%s" % (pref, value)]
+            commandline += ["--pref", "{}:{}".format(pref, value)]
         _prefs = [(i, Preferences.cast(j)) for i, j in _prefs]
         self.compare_generated(_prefs, commandline)
 
@@ -138,14 +138,14 @@ general.warnOnAboutConfig = False
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
         prefs1 = [("mr.t.quotes", "i aint getting on no plane!")]
         profile.set_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines))
         self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines))
 
@@ -162,14 +162,14 @@ general.warnOnAboutConfig = False
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
         prefs1 = [("mr.t.quotes", "i aint getting on no plane!")]
         profile.set_persistent_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines))
         self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines))
 
@@ -187,7 +187,7 @@ general.warnOnAboutConfig = False
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
@@ -195,7 +195,7 @@ general.warnOnAboutConfig = False
                   ("zoom.minPercent", 30)]
         profile.set_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(bool([line for line in lines
                               if line.startswith('#MozRunner Prefs Start')]))
         self.assertTrue(bool([line for line in lines
@@ -206,7 +206,7 @@ general.warnOnAboutConfig = False
                   ("webgl.verbose", 'false')]
         profile.set_preferences(prefs2)
         self.assertEqual(prefs1 + prefs2, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(len([line for line in lines
                              if line.startswith('#MozRunner Prefs Start')]) == 2)
         self.assertTrue(len([line for line in lines
@@ -216,7 +216,7 @@ general.warnOnAboutConfig = False
         profile.clean_preferences()
         final_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(final_prefs)
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue('#MozRunner Prefs Start' not in lines)
         self.assertTrue('#MozRunner Prefs End' not in lines)
 
@@ -233,7 +233,7 @@ user_pref("webgl.enabled_for_all_sites", true);
 user_pref("webgl.force-enabled", true);
 """
             user_js = os.path.join(tempdir, 'user.js')
-            f = file(user_js, 'w')
+            f = open(user_js, 'w')
             f.write(contents)
             f.close()
 
diff --git a/testing/mozbase/mozprofile/tests/test_profile_view.py b/testing/mozbase/mozprofile/tests/test_profile_view.py
index 2e10a913bd..f6a56e708d 100644
--- a/testing/mozbase/mozprofile/tests/test_profile_view.py
+++ b/testing/mozbase/mozprofile/tests/test_profile_view.py
@@ -20,9 +20,9 @@ class TestProfilePrint(unittest.TestCase):
         test the summary function
         """
 
-        keys = set(['Files', 'Path', 'user.js'])
+        keys = {'Files', 'Path', 'user.js'}
         ff_prefs = mozprofile.FirefoxProfile.preferences  # shorthand
-        pref_string = '\n'.join(['%s: %s' % (key, ff_prefs[key])
+        pref_string = '\n'.join(['{}: {}'.format(key, ff_prefs[key])
                                  for key in sorted(ff_prefs.keys())])
 
         tempdir = tempfile.mkdtemp()
@@ -57,17 +57,17 @@ class TestProfilePrint(unittest.TestCase):
 
         # diff two profiles
         diff = dict(mozprofile.diff(profile1, profile2))
-        self.assertEqual(diff.keys(), ['user.js'])
+        self.assertEqual(list(diff.keys()), ['user.js'])
         lines = [line.strip() for line in diff['user.js'].splitlines()]
         self.assertTrue('+foo: bar' in lines)
 
         # diff a blank vs FirefoxProfile
         ff_profile = mozprofile.FirefoxProfile()
         diff = dict(mozprofile.diff(profile2, ff_profile))
-        self.assertEqual(diff.keys(), ['user.js'])
+        self.assertEqual(list(diff.keys()), ['user.js'])
         lines = [line.strip() for line in diff['user.js'].splitlines()]
         self.assertTrue('-foo: bar' in lines)
-        ff_pref_lines = ['+%s: %s' % (key, value)
+        ff_pref_lines = ['+{}: {}'.format(key, value)
                          for key, value in mozprofile.FirefoxProfile.preferences.items()]
         self.assertTrue(set(ff_pref_lines).issubset(lines))
 
diff --git a/testing/mozbase/mozprofile/tests/test_webapps.py b/testing/mozbase/mozprofile/tests/test_webapps.py
index 4db992d696..e72bb5ae4e 100755
--- a/testing/mozbase/mozprofile/tests/test_webapps.py
+++ b/testing/mozbase/mozprofile/tests/test_webapps.py
@@ -94,7 +94,7 @@ class WebappTest(unittest.TestCase):
         self.assertEqual(len(webapps), 2)
         self.assertTrue(webapp_1 in webapps)
         self.assertTrue(webapp_2 in webapps)
-        self.assertNotEquals(webapps[0], webapps[1])
+        self.assertNotEqual(webapps[0], webapps[1])
 
         # Insert a webapp object
         webapps.insert(1, webapp_3)
diff --git a/testing/mozbase/mozrunner/mozrunner/__init__.py b/testing/mozbase/mozrunner/mozrunner/__init__.py
index 0fec5c2386..5753de41f8 100644
--- a/testing/mozbase/mozrunner/mozrunner/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/__init__.py
@@ -6,6 +6,6 @@ from .cli import *
 from .errors import *
 from .runners import *
 
-import base
-import devices
-import utils
+from . import base
+from . import devices
+from . import utils
diff --git a/testing/mozbase/mozrunner/mozrunner/application.py b/testing/mozbase/mozrunner/mozrunner/application.py
index 6734487ae6..eb874cfa5a 100644
--- a/testing/mozbase/mozrunner/mozrunner/application.py
+++ b/testing/mozbase/mozrunner/mozrunner/application.py
@@ -15,6 +15,7 @@ from mozprofile import (
     MetroFirefoxProfile,
     ThunderbirdProfile
 )
+import six
 
 here = os.path.abspath(os.path.dirname(__file__))
 
@@ -31,12 +32,11 @@ def get_app_context(appname):
     return context_map[appname]
 
 
-class DefaultContext(object):
+class DefaultContext:
     profile_class = Profile
 
 
-class RemoteContext(object):
-    __metaclass__ = ABCMeta
+class RemoteContext(six.with_metaclass(ABCMeta)):
     _dm = None
     _remote_profile = None
     _adb = None
@@ -243,15 +243,15 @@ class B2GContext(RemoteContext):
             self.dm.shellCheckOutput(['touch', self.remote_settings_db])
 
 
-class FirefoxContext(object):
+class FirefoxContext:
     profile_class = FirefoxProfile
 
 
-class ThunderbirdContext(object):
+class ThunderbirdContext:
     profile_class = ThunderbirdProfile
 
 
-class MetroContext(object):
+class MetroContext:
     profile_class = MetroFirefoxProfile
 
     def __init__(self, binary=None):
diff --git a/testing/mozbase/mozrunner/mozrunner/base/browser.py b/testing/mozbase/mozrunner/mozrunner/base/browser.py
index 6fc7348d58..9b53d09d34 100644
--- a/testing/mozbase/mozrunner/mozrunner/base/browser.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py
@@ -35,7 +35,7 @@ class GeckoRuntimeRunner(BaseRunner):
         if sys.platform == 'linux2' and self.binary.endswith('-bin'):
             dirname = os.path.dirname(self.binary)
             if os.environ.get('LD_LIBRARY_PATH', None):
-                self.env['LD_LIBRARY_PATH'] = '%s:%s' % (os.environ['LD_LIBRARY_PATH'], dirname)
+                self.env['LD_LIBRARY_PATH'] = '{}:{}'.format(os.environ['LD_LIBRARY_PATH'], dirname)
             else:
                 self.env['LD_LIBRARY_PATH'] = dirname
 
diff --git a/testing/mozbase/mozrunner/mozrunner/base/device.py b/testing/mozbase/mozrunner/mozrunner/base/device.py
index 6eeef042f4..14b2ba59b9 100644
--- a/testing/mozbase/mozrunner/mozrunner/base/device.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/device.py
@@ -2,8 +2,8 @@
 # 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 print_function
 
+from __future__ import print_function
 import datetime
 import re
 import signal
@@ -59,8 +59,8 @@ class DeviceRunner(BaseRunner):
         if self.app_ctx.dm._deviceSerial:
             cmd.extend(['-s', self.app_ctx.dm._deviceSerial])
         cmd.append('shell')
-        for k, v in self._device_env.iteritems():
-            cmd.append('%s=%s' % (k, v))
+        for k, v in self._device_env.items():
+            cmd.append('{}={}'.format(k, v))
         cmd.append(self.app_ctx.remote_binary)
         return cmd
 
@@ -87,7 +87,7 @@ class DeviceRunner(BaseRunner):
                 break
             time.sleep(1)
         else:
-            print("timed out waiting for '%s' process to start" % self.app_ctx.remote_process)
+            print(("timed out waiting for '%s' process to start" % self.app_ctx.remote_process))
 
         if not self.device.wait_for_net():
             raise Exception("Failed to get a network connection")
@@ -108,17 +108,17 @@ class DeviceRunner(BaseRunner):
             self.app_ctx.dm.killProcess(
                 self.app_ctx.remote_process, sig=sig)
             if not _wait_for_shutdown(remote_pid) and sig is not None:
-                print("timed out waiting for '%s' process to exit, trying "
+                print(("timed out waiting for '%s' process to exit, trying "
                       "without signal {}".format(
-                          self.app_ctx.remote_process, sig))
+                          self.app_ctx.remote_process, sig)))
 
             # need to call adb stop otherwise the system will attempt to
             # restart the process
             remote_pid = self.is_running() or remote_pid
             self.app_ctx.stop_application()
             if not _wait_for_shutdown(remote_pid):
-                print("timed out waiting for '%s' process to exit".format(
-                    self.app_ctx.remote_process))
+                print(("timed out waiting for '%s' process to exit".format(
+                    self.app_ctx.remote_process)))
 
     def is_running(self):
         return self.app_ctx.dm.processExist(self.app_ctx.remote_process)
@@ -137,7 +137,7 @@ class DeviceRunner(BaseRunner):
             timeout = self.output_timeout
             msg = "%s with no output" % msg
 
-        print(msg % (self.last_test, timeout))
+        print((msg % (self.last_test, timeout)))
         self.check_for_crashes()
 
     def on_finish(self):
@@ -163,7 +163,7 @@ class DeviceRunner(BaseRunner):
 class FennecRunner(DeviceRunner):
 
     def __init__(self, cmdargs=None, **kwargs):
-        super(FennecRunner, self).__init__(**kwargs)
+        super().__init__(**kwargs)
         self.cmdargs = cmdargs or []
 
     @property
@@ -178,7 +178,7 @@ class FennecRunner(DeviceRunner):
         app_params.extend(self.cmdargs)
         am_subcommand.extend(["--es", "args", "'%s'" % " ".join(app_params)])
         # Append env variables in the form |--es env0 MOZ_CRASHREPORTER=1|
-        for (count, (k, v)) in enumerate(self._device_env.iteritems()):
-            am_subcommand.extend(["--es", "env%d" % count, "%s=%s" % (k, v)])
+        for (count, (k, v)) in enumerate(self._device_env.items()):
+            am_subcommand.extend(["--es", "env%d" % count, "{}={}".format(k, v)])
         cmd.append("%s" % " ".join(am_subcommand))
         return cmd
diff --git a/testing/mozbase/mozrunner/mozrunner/base/runner.py b/testing/mozbase/mozrunner/mozrunner/base/runner.py
index 98628f6f33..f187bcf680 100644
--- a/testing/mozbase/mozrunner/mozrunner/base/runner.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/runner.py
@@ -10,6 +10,7 @@ import traceback
 
 from mozlog import get_default_logger
 from mozprocess import ProcessHandler
+import six
 try:
     import mozcrash
 except ImportError:
@@ -19,11 +20,10 @@ from ..application import DefaultContext
 from ..errors import RunnerNotStartedError
 
 
-class BaseRunner(object):
+class BaseRunner(six.with_metaclass(ABCMeta)):
     """
     The base runner class for all mozrunner objects, both local and remote.
     """
-    __metaclass__ = ABCMeta
     last_test = 'mozrunner-startup'
     process_handler = None
     timeout = None
@@ -34,7 +34,7 @@ class BaseRunner(object):
                  dump_save_path=None, addons=None):
         self.app_ctx = app_ctx or DefaultContext()
 
-        if isinstance(profile, basestring):
+        if isinstance(profile, str):
             self.profile = self.app_ctx.profile_class(profile=profile,
                                                       addons=addons)
         else:
diff --git a/testing/mozbase/mozrunner/mozrunner/cli.py b/testing/mozbase/mozrunner/mozrunner/cli.py
index 9b340edb66..657f088f74 100644
--- a/testing/mozbase/mozrunner/mozrunner/cli.py
+++ b/testing/mozbase/mozrunner/mozrunner/cli.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import sys
 
@@ -63,7 +64,7 @@ class CLI(MozProfileCLI):
             self.profile_class = get_app_context(app).profile_class
         except KeyError:
             self.parser.error('Application "%s" unknown (should be one of "%s")' %
-                              (app, ', '.join(runners.keys())))
+                              (app, ', '.join(list(runners.keys()))))
 
     def add_options(self, parser):
         """add options to the parser"""
@@ -95,7 +96,7 @@ class CLI(MozProfileCLI):
 
     def command_args(self):
         """additional arguments for the mozilla application"""
-        return map(os.path.expanduser, self.options.appArgs)
+        return list(map(os.path.expanduser, self.options.appArgs))
 
     def runner_args(self):
         """arguments to instantiate the runner class"""
@@ -137,7 +138,7 @@ class CLI(MozProfileCLI):
         # attach a debugger if specified
         debug_args, interactive = self.debugger_arguments()
         runner.start(debug_args=debug_args, interactive=interactive)
-        print 'Starting: ' + ' '.join(runner.command)
+        print(('Starting: ' + ' '.join(runner.command)))
         try:
             runner.wait()
         except KeyboardInterrupt:
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/__init__.py b/testing/mozbase/mozrunner/mozrunner/devices/__init__.py
index bdb7586c90..26f816ab17 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/__init__.py
@@ -2,12 +2,12 @@
 # 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 emulator import BaseEmulator, Emulator, EmulatorAVD
-from base import Device
+from .emulator import BaseEmulator, Emulator, EmulatorAVD
+from .base import Device
 
-import emulator_battery
-import emulator_geo
-import emulator_screen
+from . import emulator_battery
+from . import emulator_geo
+from . import emulator_screen
 
 __all__ = ['BaseEmulator', 'Emulator', 'EmulatorAVD', 'Device',
            'emulator_battery', 'emulator_geo', 'emulator_screen']
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
index 0052f473c9..6670c66774 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import fileinput
 import glob
 import os
@@ -12,8 +13,8 @@ import signal
 import sys
 import telnetlib
 import time
-import urlparse
-import urllib2
+import six.moves.urllib.parse
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 from distutils.spawn import find_executable
 
 from mozdevice import DeviceManagerADB, DMError
@@ -96,7 +97,7 @@ def verify_android_device(build_obj, install=False, xre=False, debugger=False, v
     if (len(devices) > 0) and ('device' in [d[1] for d in devices]):
         device_verified = True
     elif emulator.is_available():
-        response = raw_input(
+        response = input(
             "No Android devices connected. Start an emulator? (Y/n) ").strip()
         if response.lower().startswith('y') or response == '':
             if not emulator.check_avd():
@@ -124,7 +125,7 @@ def verify_android_device(build_obj, install=False, xre=False, debugger=False, v
         installed = emulator.dm.shellCheckOutput(['pm', 'list',
                                                   'packages', 'org.mozilla.'])
         if 'fennec' not in installed and 'firefox' not in installed:
-            response = raw_input(
+            response = input(
                 "It looks like Firefox is not installed on this device.\n"
                 "Install Firefox? (Y/n) ").strip()
             if response.lower().startswith('y') or response == '':
@@ -153,7 +154,7 @@ def verify_android_device(build_obj, install=False, xre=False, debugger=False, v
                     break
         if err:
             _log_info("Host utilities not found: %s" % err)
-            response = raw_input(
+            response = input(
                 "Download and setup your host utilities? (Y/n) ").strip()
             if response.lower().startswith('y') or response == '':
                 _log_info("Installing host utilities. This may take a while...")
@@ -188,7 +189,7 @@ def verify_android_device(build_obj, install=False, xre=False, debugger=False, v
             err = '%s not found' % gdb_path
         if err:
             _log_info("JimDB (%s) not found: %s" % (build_platform, err))
-            response = raw_input(
+            response = input(
                 "Download and setup JimDB (%s)? (Y/n) " % build_platform).strip()
             if response.lower().startswith('y') or response == '':
                 host_platform = _get_host_platform()
@@ -252,7 +253,7 @@ def run_firefox_for_android(build_obj, params):
         cmd = ['am', 'start', '-a', 'android.activity.MAIN', '-n', app]
         if params:
             for p in params:
-                if urlparse.urlparse(p).scheme != "":
+                if six.moves.urllib.parse.urlparse(p).scheme != "":
                     cmd.extend(['-d', p])
                     params.remove(p)
                     break
@@ -570,7 +571,7 @@ class AndroidEmulator(object):
         return telnet_ok
 
     def _get_avd_type(self, requested):
-        if requested in AVD_DICT.keys():
+        if requested in list(AVD_DICT.keys()):
             return requested
         if self.substs:
             if not self.substs['TARGET_CPU'].startswith('arm'):
@@ -646,23 +647,23 @@ def _find_sdk_exe(substs, exe, tools):
 
 def _log_debug(text):
     if verbose_logging:
-        print "DEBUG: %s" % text
+        print(("DEBUG: %s" % text))
 
 
 def _log_warning(text):
-    print "WARNING: %s" % text
+    print(("WARNING: %s" % text))
 
 
 def _log_info(text):
-    print "%s" % text
+    print(("%s" % text))
 
 
 def _download_file(url, filename, path):
-    f = urllib2.urlopen(url)
+    f = six.moves.urllib.request.urlopen(url)
     if not os.path.isdir(path):
         try:
             os.makedirs(path)
-        except Exception, e:
+        except Exception as e:
             _log_warning(str(e))
             return False
     local_file = open(os.path.join(path, filename), 'wb')
@@ -676,7 +677,7 @@ def _get_tooltool_manifest(substs, src_path, dst_path, filename):
     if not os.path.isdir(dst_path):
         try:
             os.makedirs(dst_path)
-        except Exception, e:
+        except Exception as e:
             _log_warning(str(e))
     copied = False
     if substs and 'top_srcdir' in substs:
@@ -750,13 +751,13 @@ def _update_gdbinit(substs, path):
         # update existing objdir/srcroot in place
         for line in fileinput.input(path, inplace=True):
             if "feninit.default.objdir" in line and substs and 'MOZ_BUILD_ROOT' in substs:
-                print("python feninit.default.objdir = '%s'" % substs['MOZ_BUILD_ROOT'])
+                print(("python feninit.default.objdir = '%s'" % substs['MOZ_BUILD_ROOT']))
                 obj_replaced = True
             elif "feninit.default.srcroot" in line and substs and 'top_srcdir' in substs:
-                print("python feninit.default.srcroot = '%s'" % substs['top_srcdir'])
+                print(("python feninit.default.srcroot = '%s'" % substs['top_srcdir']))
                 src_replaced = True
             else:
-                print(line.strip())
+                print((line.strip()))
         # append objdir/srcroot if not updated
         if (not obj_replaced) and substs and 'MOZ_BUILD_ROOT' in substs:
             with open(path, "a") as f:
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/autophone.py b/testing/mozbase/mozrunner/mozrunner/devices/autophone.py
index 3b4913028e..b648a13f71 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/autophone.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/autophone.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import glob
 import json
 import logging
@@ -13,15 +14,15 @@ import sys
 import threading
 import time
 import which
-import BaseHTTPServer
-import SimpleHTTPServer
+import six.moves.BaseHTTPServer
+import six.moves.SimpleHTTPServer
 
 from mozbuild.virtualenv import VirtualenvManager
 from mozdevice import DeviceManagerADB
 from mozprocess import ProcessHandler
 
 
-class AutophoneRunner(object):
+class AutophoneRunner:
     """
        Supporting the mach 'autophone' command: configure, run autophone.
     """
@@ -47,7 +48,7 @@ class AutophoneRunner(object):
             self.build_obj.log(logging.WARN, "autophone", {},
                                "*** This will delete %s and reset your "
                                "'mach autophone' configuration! ***" % dir)
-            response = raw_input(
+            response = input(
                 "Proceed with deletion? (y/N) ").strip()
             if response.lower().startswith('y'):
                 os.remove(self.CONFIG_FILE)
@@ -64,7 +65,7 @@ class AutophoneRunner(object):
             with open(self.CONFIG_FILE, 'w') as f:
                 json.dump(self.config, f)
             if self.verbose:
-                print("saved configuration: %s" % self.config)
+                print(("saved configuration: %s" % self.config))
         except:
             self.build_obj.log(logging.ERROR, "autophone", {},
                                "unable to save 'mach autophone' "
@@ -79,10 +80,10 @@ class AutophoneRunner(object):
         """
         if os.path.exists(self.CONFIG_FILE):
             try:
-                with open(self.CONFIG_FILE, 'r') as f:
+                with open(self.CONFIG_FILE) as f:
                     self.config = json.load(f)
                 if self.verbose:
-                    print("loaded configuration: %s" % self.config)
+                    print(("loaded configuration: %s" % self.config))
             except:
                 self.build_obj.log(logging.ERROR, "autophone", {},
                                    "unable to load 'mach autophone' "
@@ -100,7 +101,7 @@ class AutophoneRunner(object):
         if not dir:
             dir = os.path.join(os.path.expanduser('~'), 'mach-autophone')
         if os.path.exists(os.path.join(dir, '.git')):
-            response = raw_input(
+            response = input(
                 "Run autophone from existing directory, %s (Y/n) " % dir).strip()
             if 'n' not in response.lower():
                 self.build_obj.log(logging.INFO, "autophone", {},
@@ -109,7 +110,7 @@ class AutophoneRunner(object):
         self.build_obj.log(logging.INFO, "autophone", {},
                            "Unable to find an existing autophone directory. "
                            "Let's setup a new one...")
-        response = raw_input(
+        response = input(
             "Enter location of new autophone directory: [%s] " % dir).strip()
         if response != '':
             dir = response
@@ -160,7 +161,7 @@ class AutophoneRunner(object):
         keep_going = True
         device_ini = os.path.join(self.config['base-dir'], 'devices.ini')
         if os.path.exists(device_ini):
-            response = raw_input(
+            response = input(
                 "Use existing device configuration at %s? (Y/n) " % device_ini).strip()
             if 'n' not in response.lower():
                 self.build_obj.log(logging.INFO, "autophone", {},
@@ -170,10 +171,10 @@ class AutophoneRunner(object):
         self.build_obj.log(logging.INFO, "autophone", {},
                            "You must configure at least one Android device "
                            "before running autophone.")
-        response = raw_input(
+        response = input(
             "Configure devices now? (Y/n) ").strip()
         if response.lower().startswith('y') or response == '':
-            response = raw_input(
+            response = input(
                 "Connect your rooted Android test device(s) with usb and press Enter ")
             adb_path = 'adb'
             try:
@@ -187,10 +188,10 @@ class AutophoneRunner(object):
                 try:
                     adb_path = which.which('adb')
                 except which.WhichError:
-                    adb_path = raw_input(
+                    adb_path = input(
                         "adb not found. Enter path to adb: ").strip()
             if self.verbose:
-                print("Using adb at %s" % adb_path)
+                print(("Using adb at %s" % adb_path))
             dm = DeviceManagerADB(autoconnect=False, adbPath=adb_path, retryLimit=1)
             device_index = 1
             try:
@@ -232,7 +233,7 @@ class AutophoneRunner(object):
                            "describing the type(s) of test(s) to run.")
         test_options = []
         for ini in glob.glob(os.path.join(dir, 'tests', '*.ini')):
-            with open(ini, 'r') as f:
+            with open(ini) as f:
                 content = f.readlines()
                 for line in content:
                     if line.startswith('# @mach@ '):
@@ -248,14 +249,14 @@ class AutophoneRunner(object):
                                "These test manifests are available:")
             index = 1
             for option in test_options:
-                print("%d. %s" % (index, option[0]))
+                print(("%d. %s" % (index, option[0])))
                 index += 1
             highest = index - 1
             path = None
             while not path:
                 path = None
                 self.webserver_required = False
-                response = raw_input(
+                response = input(
                     "Select test manifest (1-%d, or path to test manifest) " % highest).strip()
                 if os.path.isfile(response):
                     path = response
@@ -284,7 +285,7 @@ class AutophoneRunner(object):
             response = ""
             default = self.config['test-manifest'] or ""
             while not os.path.isfile(response):
-                response = raw_input(
+                response = input(
                     "Enter path to a test manifest: [%s] " % default).strip()
                 if response == "":
                     response = default
@@ -305,13 +306,13 @@ class AutophoneRunner(object):
                 f.write("""\
 # Created by 'mach autophone'
 [runtests]
-xre_path = %s
-utility_path = %s
+xre_path = {}
+utility_path = {}
 console_level = DEBUG
 log_level = DEBUG
-time_out = 300""" % (xre_path, xre_path))
+time_out = 300""".format(xre_path, xre_path))
             if self.verbose:
-                print("Created %s with host utilities path %s" % (defaults_path, xre_path))
+                print(("Created {} with host utilities path {}".format(defaults_path, xre_path)))
         except:
             self.build_obj.log(logging.ERROR, "autophone", {},
                                "Unable to create %s" % defaults_path)
@@ -325,7 +326,7 @@ time_out = 300""" % (xre_path, xre_path))
         """
         defaults_path = os.path.join(self.config['base-dir'], 'configs', 'unittest-defaults.ini')
         if os.path.isfile(defaults_path):
-            response = raw_input(
+            response = input(
                 "Use existing unit test configuration at %s? (Y/n) " % defaults_path).strip()
             if 'n' in response.lower():
                 os.remove(defaults_path)
@@ -343,7 +344,7 @@ time_out = 300""" % (xre_path, xre_path))
                 self.build_obj.log(logging.INFO, "autophone", {},
                                    "Some tests require access to 'host utilities' "
                                    "such as xpcshell.")
-                xre_path = raw_input(
+                xre_path = input(
                     "Enter path to host utilities directory: ").strip()
                 if not xre_path or not os.path.isdir(xre_path) or \
                    not os.path.isfile(os.path.join(xre_path, 'xpcshell')):
@@ -366,7 +367,7 @@ time_out = 300""" % (xre_path, xre_path))
         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         s.connect(('8.8.8.8', 0))
         ip = s.getsockname()[0]
-        response = raw_input(
+        response = input(
             "IP address of interface to use for phone callbacks [%s] " % ip).strip()
         if response == "":
             response = ip
@@ -381,10 +382,10 @@ time_out = 300""" % (xre_path, xre_path))
         if self.webserver_required:
             self.build_obj.log(logging.INFO, "autophone", {},
                                "Some of your selected tests require a webserver.")
-            response = raw_input("Start a webserver now? [Y/n] ").strip()
+            response = input("Start a webserver now? [Y/n] ").strip()
             parts = []
             while len(parts) != 2:
-                response2 = raw_input(
+                response2 = input(
                     "Webserver address? [%s:8100] " % self.ipaddr).strip()
                 if response2 == "":
                     parts = [self.ipaddr, "8100"]
@@ -496,7 +497,7 @@ time_out = 300""" % (xre_path, xre_path))
                 "Type 'trigger', 'help', 'quit', or an autophone command.")
         quitting = False
         while self.thread.isAlive() and not quitting:
-            response = raw_input(
+            response = input(
                 "autophone command? ").strip().lower()
             if response == "help":
                 self.run_process(['./ap.sh', 'autophone-help'], cwd=dir, dump=True)
@@ -545,7 +546,7 @@ quit
         highest = 4
         choice = 0
         while (choice < 1 or choice > highest):
-            response = raw_input(
+            response = input(
                 "Build selection type? (1-%d) " % highest).strip()
             try:
                 choice = int(response)
@@ -556,18 +557,18 @@ quit
         if choice == 1:
             options = ["latest"]
         elif choice == 2:
-            url = raw_input(
+            url = input(
                 "Enter url of build to test; may be an http or file schema ").strip()
             options = ["--build-url=%s" % url]
         elif choice == 3:
-            response = raw_input(
+            response = input(
                 "Enter Build ID, eg 20120403063158 ").strip()
             options = [response]
         elif choice == 4:
-            start = raw_input(
+            start = input(
                 "Enter start build date or date-time, "
                 "e.g. 2012-04-03 or 2012-04-03T06:31:58 ").strip()
-            end = raw_input(
+            end = input(
                 "Enter end build date or date-time, "
                 "e.g. 2012-04-03 or 2012-04-03T06:31:58 ").strip()
             options = [start, end]
@@ -577,7 +578,7 @@ quit
         self.build_obj.log(
             logging.INFO, "autophone", {},
             "If not specified, 'mozilla-central' is assumed.")
-        repo = raw_input(
+        repo = input(
             "Enter repository name: ").strip()
         if len(repo) > 0:
             options.extend(["--repo=%s" % repo])
@@ -585,7 +586,7 @@ quit
             self.build_obj.log(
                 logging.INFO, "autophone", {},
                 "You may optionally specify the build location, like 'nightly' or 'tinderbox'.")
-            location = raw_input(
+            location = input(
                 "Enter build location: ").strip()
             if len(location) > 0:
                 options.extend(["--build-location=%s" % location])
@@ -612,7 +613,7 @@ quit
         self.threadweb.start()
 
     def run_webserver(self):
-        class AutoHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
+        class AutoHTTPRequestHandler(six.moves.SimpleHTTPServer.SimpleHTTPRequestHandler):
             # A simple request handler with logging suppressed.
 
             def log_message(self, format, *args):
@@ -620,7 +621,7 @@ quit
 
         os.chdir(self.config['base-dir'])
         address = (self.webserver_addr, self.webserver_port)
-        self.httpd = BaseHTTPServer.HTTPServer(address, AutoHTTPRequestHandler)
+        self.httpd = six.moves.BaseHTTPServer.HTTPServer(address, AutoHTTPRequestHandler)
         try:
             self.httpd.serve_forever()
         except KeyboardInterrupt:
@@ -633,7 +634,7 @@ quit
 
         if self.verbose:
             self.build_obj.log(logging.INFO, "autophone", {},
-                               "Running '%s' in '%s'" % (cmd, cwd))
+                               "Running '{}' in '{}'".format(cmd, cwd))
         proc = ProcessHandler(cmd, cwd=cwd, processOutputLine=_processOutput,
                               processStderrLine=_processOutput)
         proc.run()
@@ -647,5 +648,5 @@ quit
                 proc.kill(signal.SIGTERM)
         if not proc_complete:
             if not self.verbose:
-                print(proc.output)
+                print((proc.output))
         return proc_complete
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/base.py b/testing/mozbase/mozrunner/mozrunner/devices/base.py
index b5cf2b58fb..a0d9004d38 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/base.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/base.py
@@ -1,4 +1,5 @@
-from ConfigParser import (
+from __future__ import print_function
+from configparser import (
     ConfigParser,
     RawConfigParser
 )
@@ -89,7 +90,7 @@ class Device(object):
                 break
             time.sleep(1)
         else:
-            print "timed out waiting for profiles.ini"
+            print("timed out waiting for profiles.ini")
 
         local_profiles_ini = tempfile.NamedTemporaryFile()
         self.dm.getFile(self.app_ctx.remote_profiles_ini, local_profiles_ini.name)
@@ -175,7 +176,7 @@ class Device(object):
         :param busybox: Path to busybox binary to install.
         """
         self.dm.remount()
-        print 'pushing %s' % self.app_ctx.remote_busybox
+        print(('pushing %s' % self.app_ctx.remote_busybox))
         self.dm.pushFile(busybox, self.app_ctx.remote_busybox, retryLimit=10)
         # TODO for some reason using dm.shellCheckOutput doesn't work,
         #      while calling adb shell directly does.
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/emulator.py b/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
index adeae27ed7..5a14aaa7ba 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
@@ -19,7 +19,7 @@ from .emulator_screen import EmulatorScreen
 from ..errors import TimeoutException
 
 
-class ArchContext(object):
+class ArchContext:
 
     def __init__(self, arch, context, binary=None, avd=None, extra_args=None):
         homedir = getattr(context, 'homedir', '')
@@ -49,7 +49,7 @@ class ArchContext(object):
             self.extra_args.extend(extra_args)
 
 
-class SDCard(object):
+class SDCard:
 
     def __init__(self, emulator, size):
         self.emulator = emulator
@@ -82,7 +82,7 @@ class BaseEmulator(Device):
         self.arch = ArchContext(kwargs.pop('arch', 'arm'), app_ctx,
                                 binary=kwargs.pop('binary', None),
                                 avd=kwargs.pop('avd', None))
-        super(BaseEmulator, self).__init__(app_ctx, **kwargs)
+        super().__init__(app_ctx, **kwargs)
         self.tmpdir = tempfile.mkdtemp()
         # These rely on telnet
         self.battery = EmulatorBattery(self)
@@ -125,7 +125,7 @@ class BaseEmulator(Device):
 
         devices = set(self._get_online_devices())
         now = datetime.datetime.now()
-        while (devices - original_devices) == set([]):
+        while (devices - original_devices) == set():
             time.sleep(1)
             # Sometimes it takes more than 60s to launch emulator, so we
             # increase timeout value to 180s. Please see bug 1143380.
@@ -150,7 +150,7 @@ class BaseEmulator(Device):
         if self.connected:
             return
 
-        super(BaseEmulator, self).connect()
+        super().connect()
         serial = self.serial or self.dm._deviceSerial
         self.port = int(serial[serial.rindex('-') + 1:])
 
@@ -158,7 +158,7 @@ class BaseEmulator(Device):
         """
         Cleans up and kills the emulator, if it was started by mozrunner.
         """
-        super(BaseEmulator, self).cleanup()
+        super().cleanup()
         if self.proc:
             self.proc.kill()
             self.proc = None
@@ -196,7 +196,7 @@ class Emulator(BaseEmulator):
 
     def __init__(self, app_ctx, arch, resolution=None, sdcard=None, userdata=None,
                  no_window=None, binary=None, **kwargs):
-        super(Emulator, self).__init__(app_ctx, arch=arch, binary=binary, **kwargs)
+        super().__init__(app_ctx, arch=arch, binary=binary, **kwargs)
 
         # emulator args
         self.resolution = resolution or '320x480'
@@ -218,7 +218,7 @@ class Emulator(BaseEmulator):
         """
         Arguments to pass into the emulator binary.
         """
-        qemu_args = super(Emulator, self).args
+        qemu_args = super().args
         qemu_args.extend([
             '-kernel', self.arch.kernel,
             '-sysdir', self.arch.sysdir,
@@ -245,7 +245,7 @@ class Emulator(BaseEmulator):
         if self.connected:
             return
 
-        super(Emulator, self).connect()
+        super().connect()
         self.geo.set_default_location()
         self.screen.initialize()
 
@@ -256,7 +256,7 @@ class Emulator(BaseEmulator):
         """
         Cleans up and kills the emulator, if it was started by mozrunner.
         """
-        super(Emulator, self).cleanup()
+        super().cleanup()
         # Remove temporary files
         self.userdata.close()
 
@@ -264,7 +264,7 @@ class Emulator(BaseEmulator):
 class EmulatorAVD(BaseEmulator):
 
     def __init__(self, app_ctx, binary, avd, port=5554, **kwargs):
-        super(EmulatorAVD, self).__init__(app_ctx, binary=binary, avd=avd, **kwargs)
+        super().__init__(app_ctx, binary=binary, avd=avd, **kwargs)
         self.port = port
 
     @property
@@ -272,7 +272,7 @@ class EmulatorAVD(BaseEmulator):
         """
         Arguments to pass into the emulator binary.
         """
-        qemu_args = super(EmulatorAVD, self).args
+        qemu_args = super().args
         qemu_args.extend(['-avd', self.arch.avd,
                           '-port', str(self.port)])
         qemu_args.extend(self.arch.extra_args)
@@ -285,4 +285,4 @@ class EmulatorAVD(BaseEmulator):
         env = os.environ
         env['ANDROID_AVD_HOME'] = self.app_ctx.avd_home
 
-        super(EmulatorAVD, self).start()
+        super().start()
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py b/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
index 6f389152b2..9d7aab5baa 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
@@ -3,7 +3,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
-class EmulatorBattery(object):
+class EmulatorBattery:
 
     def __init__(self, emulator):
         self.emulator = emulator
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py b/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
index a8ec0e0899..65bd56f3c8 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
@@ -3,7 +3,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
-class EmulatorGeo(object):
+class EmulatorGeo:
 
     def __init__(self, emulator):
         self.emulator = emulator
@@ -14,4 +14,4 @@ class EmulatorGeo(object):
         self.set_location(self.lon, self.lat)
 
     def set_location(self, lon, lat):
-        self.emulator._run_telnet('geo fix %0.5f %0.5f' % (self.lon, self.lat))
+        self.emulator._run_telnet('geo fix {:0.5f} {:0.5f}'.format(self.lon, self.lat))
diff --git a/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py b/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
index 58bdda8124..fa18567b5a 100644
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
@@ -3,7 +3,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
-class EmulatorScreen(object):
+class EmulatorScreen:
     """Class for screen related emulator commands."""
 
     SO_PORTRAIT_PRIMARY = 'portrait-primary'
diff --git a/testing/mozbase/mozrunner/mozrunner/utils.py b/testing/mozbase/mozrunner/mozrunner/utils.py
index c26055f300..7c62df732c 100755
--- a/testing/mozbase/mozrunner/mozrunner/utils.py
+++ b/testing/mozbase/mozrunner/mozrunner/utils.py
@@ -6,6 +6,7 @@
 
 """Utility functions for mozrunner"""
 
+from __future__ import print_function
 import mozinfo
 import os
 import sys
@@ -63,7 +64,7 @@ def findInPath(fileName, path=os.environ['PATH']):
 
 if __name__ == '__main__':
     for i in sys.argv[1:]:
-        print findInPath(i)
+        print((findInPath(i)))
 
 
 def _find_marionette_in_args(*args, **kwargs):
diff --git a/testing/mozbase/mozrunner/tests/test_crash.py b/testing/mozbase/mozrunner/tests/test_crash.py
index 455fc5f72d..3048ed9f77 100644
--- a/testing/mozbase/mozrunner/tests/test_crash.py
+++ b/testing/mozbase/mozrunner/tests/test_crash.py
@@ -3,7 +3,7 @@
 # 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/.
 
-import mock
+from unittest import mock
 
 import mozrunnertest
 
diff --git a/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py b/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
index 56c62cb23c..8f42d31c2f 100644
--- a/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
+++ b/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import mozinfo
 import tempfile
@@ -11,12 +12,12 @@ from mozlog.formatters.process import strstatus
 
 def printstatus(name, returncode):
     """
-    print the status of a command exit code, formatted for tbpl.
+    print(the status of a command exit code, formatted for tbpl.)
 
     Note that mozlog structured action "process_exit" should be used
     instead of that in new code.
     """
-    print "TEST-INFO | %s: %s" % (name, strstatus(returncode))
+    print(("TEST-INFO | %s: %s" % (name, strstatus(returncode))))
 
 
 def dump_screen(utilityPath, log):
@@ -56,6 +57,6 @@ def dump_screen(utilityPath, log):
             log.process_exit(utilityname, returncode)
         else:
             printstatus(utilityname, returncode)
-    except OSError, err:
+    except OSError as err:
         log.info("Failed to start %s for screenshot: %s"
                  % (utility[0], err.strerror))
diff --git a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
index 56a1f0ef70..a197e0185d 100644
--- a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
+++ b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
@@ -14,7 +14,7 @@ from collections import (
 )
 
 
-class PsutilStub(object):
+class PsutilStub:
 
     def __init__(self):
         self.sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
@@ -138,7 +138,7 @@ SystemResourceUsage = namedtuple('SystemResourceUsage',
                                   'cpu_times', 'cpu_percent', 'io', 'virt', 'swap'])
 
 
-class SystemResourceMonitor(object):
+class SystemResourceMonitor:
     """Measures system resources.
 
     Each instance measures system resources from the time it is started
diff --git a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/test/test_resource_monitor.py b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/test/test_resource_monitor.py
index b6763e20e9..657a58770b 100644
--- a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/test/test_resource_monitor.py
+++ b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/test/test_resource_monitor.py
@@ -56,7 +56,7 @@ class TestResourceMonitor(unittest.TestCase):
         monitor.stop()
 
         self.assertEqual(len(monitor.phases), 2)
-        self.assertEqual(['phase2', 'phase1'], monitor.phases.keys())
+        self.assertEqual(['phase2', 'phase1'], list(monitor.phases.keys()))
 
         all = list(monitor.range_usage())
         data1 = list(monitor.phase_usage('phase1'))
@@ -146,7 +146,7 @@ class TestResourceMonitor(unittest.TestCase):
         monitor.stop()
 
         v = monitor.min_memory_available()
-        self.assertIsInstance(v, long)
+        self.assertIsInstance(v, int)
 
         v = monitor.max_memory_percent()
         self.assertIsInstance(v, float)
diff --git a/testing/mozbase/moztest/moztest/__init__.py b/testing/mozbase/moztest/moztest/__init__.py
index 5820ed2eb6..be7852c9df 100644
--- a/testing/mozbase/moztest/moztest/__init__.py
+++ b/testing/mozbase/moztest/moztest/__init__.py
@@ -2,6 +2,6 @@
 # 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/.
 
-import adapters
+from . import adapters
 
 __all__ = ['adapters']
diff --git a/testing/mozbase/moztest/moztest/adapters/__init__.py b/testing/mozbase/moztest/moztest/adapters/__init__.py
index 46bb3c6eb6..c0c72fc22b 100644
--- a/testing/mozbase/moztest/moztest/adapters/__init__.py
+++ b/testing/mozbase/moztest/moztest/adapters/__init__.py
@@ -2,6 +2,6 @@
 # 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/.
 
-import unit
+from . import unit
 
 __all__ = ['unit']
diff --git a/testing/mozbase/moztest/moztest/adapters/unit.py b/testing/mozbase/moztest/moztest/adapters/unit.py
index cee0e05e92..3b27685b50 100644
--- a/testing/mozbase/moztest/moztest/adapters/unit.py
+++ b/testing/mozbase/moztest/moztest/adapters/unit.py
@@ -26,7 +26,7 @@ def get_test_class_name(test):
     passed in structured loggers. You can override the default by
     implementing a "get_test_class_name" method on you TestCase subclass.
     """
-    return "%s.%s" % (test.__class__.__module__,
+    return "{}.{}".format(test.__class__.__module__,
                       test.__class__.__name__)
 
 
diff --git a/testing/mozbase/moztest/moztest/output/autolog.py b/testing/mozbase/moztest/moztest/output/autolog.py
index b6c8368bd4..c5d5b77a2d 100644
--- a/testing/mozbase/moztest/moztest/output/autolog.py
+++ b/testing/mozbase/moztest/moztest/output/autolog.py
@@ -5,7 +5,7 @@
 
 from mozautolog import RESTfulAutologTestGroup
 
-from base import Output, count, long_name
+from .base import Output, count, long_name
 
 
 class AutologOutput(Output):
diff --git a/testing/mozbase/moztest/moztest/output/base.py b/testing/mozbase/moztest/moztest/output/base.py
index 7e39317fb1..9d0455a85e 100644
--- a/testing/mozbase/moztest/moztest/output/base.py
+++ b/testing/mozbase/moztest/moztest/output/base.py
@@ -3,7 +3,6 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
-from __future__ import with_statement
 from contextlib import closing
 from StringIO import StringIO
 
@@ -13,8 +12,8 @@ except ImportError:
     # abc is python 2.6+
     # from https://github.com/mozilla/mozbase/blob/master/mozdevice/mozdevice/devicemanager.py
     def abstractmethod(method):
-        line = method.func_code.co_firstlineno
-        filename = method.func_code.co_filename
+        line = method.__code__.co_firstlineno
+        filename = method.__code__.co_filename
 
         def not_implemented(*args, **kwargs):
             raise NotImplementedError('Abstract method %s at File "%s", '
@@ -23,7 +22,7 @@ except ImportError:
         return not_implemented
 
 
-class Output(object):
+class Output:
     """ Abstract base class for outputting test results """
 
     @abstractmethod
@@ -49,5 +48,5 @@ def count(iterable):
 
 def long_name(test):
     if test.test_class:
-        return '%s.%s' % (test.test_class, test.name)
+        return '{}.{}'.format(test.test_class, test.name)
     return test.name
diff --git a/testing/mozbase/moztest/moztest/output/xunit.py b/testing/mozbase/moztest/moztest/output/xunit.py
index 0d0ef7bb4d..2189d15d75 100644
--- a/testing/mozbase/moztest/moztest/output/xunit.py
+++ b/testing/mozbase/moztest/moztest/output/xunit.py
@@ -5,7 +5,7 @@
 
 import xml.dom.minidom as dom
 
-from base import Output, count
+from .base import Output, count
 from moztest.results import TestResult
 
 
@@ -16,7 +16,7 @@ class XUnitOutput(Output):
         """ Writes the xUnit formatted results to the given file object """
 
         def _extract_xml(test_result, text='', result='Pass'):
-            if not isinstance(text, basestring):
+            if not isinstance(text, str):
                 text = '\n'.join(text)
 
             cls_name = test_result.test_class
@@ -86,7 +86,7 @@ class XUnitOutput(Output):
         for tr in results_collection.tests_with_result('PASS'):
             _extract_xml(tr, result='Pass')
 
-        for cls in classes.itervalues():
+        for cls in classes.values():
             assembly.appendChild(cls)
 
         doc.appendChild(assembly)
diff --git a/testing/mozbase/moztest/moztest/results.py b/testing/mozbase/moztest/moztest/results.py
index 435665c670..495cea578e 100644
--- a/testing/mozbase/moztest/moztest/results.py
+++ b/testing/mozbase/moztest/moztest/results.py
@@ -8,7 +8,7 @@ import os
 import mozinfo
 
 
-class TestContext(object):
+class TestContext:
     """ Stores context data about the test """
 
     attrs = ['hostname', 'arch', 'env', 'os', 'os_version', 'tree', 'revision',
@@ -31,7 +31,7 @@ class TestContext(object):
         self.buildtype = buildtype
 
     def __str__(self):
-        return '%s (%s, %s)' % (self.hostname, self.os, self.arch)
+        return '{} ({}, {})'.format(self.hostname, self.os, self.arch)
 
     def __repr__(self):
         return '<%s>' % self.__str__()
@@ -46,12 +46,12 @@ class TestContext(object):
         def get(attr):
             value = getattr(self, attr)
             if isinstance(value, dict):
-                value = frozenset(value.items())
+                value = frozenset(list(value.items()))
             return value
         return hash(frozenset([get(a) for a in self.attrs]))
 
 
-class TestResult(object):
+class TestResult:
     """ Stores test result data """
 
     FAIL_RESULTS = [
@@ -84,7 +84,7 @@ class TestResult(object):
 
         msg = "Result '%s' not in possible results: %s" %\
               (result_expected, ', '.join(self.POSSIBLE_RESULTS))
-        assert isinstance(name, basestring), "name has to be a string"
+        assert isinstance(name, str), "name has to be a string"
         assert result_expected in self.POSSIBLE_RESULTS, msg
 
         self.name = name
@@ -102,12 +102,12 @@ class TestResult(object):
 
     @property
     def test_name(self):
-        return '%s.py %s.%s' % (self.test_class.split('.')[0],
+        return '{}.py {}.{}'.format(self.test_class.split('.')[0],
                                 self.test_class,
                                 self.name)
 
     def __str__(self):
-        return '%s | %s (%s) | %s' % (self.result or 'PENDING',
+        return '{} | {} ({}) | {}'.format(self.result or 'PENDING',
                                       self.name, self.test_class, self.reason)
 
     def __repr__(self):
@@ -170,7 +170,7 @@ class TestResult(object):
             raise ValueError(msg)
 
         # use lists instead of multiline strings
-        if isinstance(output, basestring):
+        if isinstance(output, str):
             output = output.splitlines()
 
         self.time_end = time_end if time_end is not None else time.time()
@@ -206,7 +206,7 @@ class TestResultCollection(list):
             self.resultClass = resultClass
 
     def __str__(self):
-        return "%s (%.2fs)\n%s" % (self.suite_name, self.time_taken,
+        return "{} ({:.2f}s)\n{}".format(self.suite_name, self.time_taken,
                                    list.__str__(self))
 
     def subset(self, predicate):
diff --git a/testing/mozbase/mozversion/mozversion/mozversion.py b/testing/mozbase/mozversion/mozversion/mozversion.py
index 5dfcd306a9..598eb1b2f2 100644
--- a/testing/mozbase/mozversion/mozversion/mozversion.py
+++ b/testing/mozbase/mozversion/mozversion/mozversion.py
@@ -3,7 +3,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import argparse
-import ConfigParser
+import six.moves.configparser
 from StringIO import StringIO
 import os
 import re
@@ -15,13 +15,13 @@ import zipfile
 import mozfile
 import mozlog
 
-import errors
+from . import errors
 
 
 INI_DATA_MAPPING = (('application', 'App'), ('platform', 'Build'))
 
 
-class Version(object):
+class Version:
 
     def __init__(self):
         self._info = {}
@@ -38,7 +38,7 @@ class Version(object):
                 self._logger.warning('Unable to find %s' % config_file)
 
     def _parse_ini_file(self, fp, type, section):
-        config = ConfigParser.RawConfigParser()
+        config = six.moves.configparser.RawConfigParser()
         config.readfp(fp)
         name_map = {'codename': 'display_name',
                     'milestone': 'version',
@@ -46,7 +46,7 @@ class Version(object):
                     'sourcestamp': 'changeset'}
         for key, value in config.items(section):
             name = name_map.get(key, key).lower()
-            self._info['%s_%s' % (type, name)] = config.has_option(
+            self._info['{}_{}'.format(type, name)] = config.has_option(
                 section, key) and config.get(section, key) or None
 
         if not self._info.get('application_display_name'):
@@ -86,7 +86,7 @@ class LocalVersion(Version):
             # .exe extension
             if not os.path.exists(binary) and not os.path.exists(binary +
                                                                  '.exe'):
-                raise IOError('Binary path does not exist: %s' % binary)
+                raise OSError('Binary path does not exist: %s' % binary)
             path = os.path.dirname(os.path.realpath(binary))
         else:
             path = os.getcwd()
@@ -146,7 +146,7 @@ class B2GVersion(Version):
             with open(gaia_commit) as f:
                 changeset, date = f.read().splitlines()
                 self._info['gaia_changeset'] = re.match(
-                    '^\w{40}$', changeset) and changeset or None
+                    r'^\w{40}$', changeset) and changeset or None
                 self._info['gaia_date'] = date
         except KeyError:
             self._logger.warning(
@@ -163,7 +163,7 @@ class LocalB2GVersion(B2GVersion):
 
         if binary:
             if not os.path.exists(binary):
-                raise IOError('Binary path does not exist: %s' % binary)
+                raise OSError('Binary path does not exist: %s' % binary)
             path = os.path.dirname(binary)
         else:
             if os.path.exists(os.path.join(os.getcwd(), 'application.ini')):
@@ -241,8 +241,8 @@ class RemoteB2GVersion(B2GVersion):
             'ro.product.device': 'device_id'}
         for line in build_props.split('\n'):
             if not line.strip().startswith('#') and '=' in line:
-                key, value = [s.strip() for s in line.split('=', 1)]
-                if key in desired_props.keys():
+                key, value = (s.strip() for s in line.split('=', 1))
+                if key in list(desired_props.keys()):
                     self._info[desired_props[key]] = value
 
         if self._info.get('device_id', '').lower() == 'flame':
@@ -292,7 +292,7 @@ def get_version(binary=None, sources=None, dm_type=None, host=None,
 
     for (key, value) in sorted(version._info.items()):
         if value:
-            version._logger.info('%s: %s' % (key, value))
+            version._logger.info('{}: {}'.format(key, value))
 
     return version._info
 
diff --git a/testing/mozbase/mozversion/tests/test_b2g.py b/testing/mozbase/mozversion/tests/test_b2g.py
index 09e0eb09e9..9a2a151114 100644
--- a/testing/mozbase/mozversion/tests/test_b2g.py
+++ b/testing/mozbase/mozversion/tests/test_b2g.py
@@ -40,7 +40,7 @@ class SourcesTest(unittest.TestCase):
         app_zip = zipfile.ZipFile(zip_path, 'w')
         if revision or date:
             app_zip.writestr('resources/gaia_commit.txt',
-                             '%s\n%s' % (revision, date))
+                             '{}\n{}'.format(revision, date))
         app_zip.close()
 
     def test_gaia_commit(self):
diff --git a/testing/mozbase/setup_development.py b/testing/mozbase/setup_development.py
index c048d504f1..93d3aa26af 100755
--- a/testing/mozbase/setup_development.py
+++ b/testing/mozbase/setup_development.py
@@ -13,6 +13,7 @@ If no arguments are given, install all packages.
 See https://wiki.mozilla.org/Auto-tools/Projects/Mozbase
 """
 
+from __future__ import print_function
 import os
 import subprocess
 import sys
@@ -57,7 +58,7 @@ def info(directory):
         call([sys.executable, 'setup.py', 'egg_info'],
              cwd=directory, stdout=PIPE)
     except subprocess.CalledProcessError:
-        print "Error running setup.py in %s" % directory
+        print(("Error running setup.py in %s" % directory))
         raise
 
     # get the .egg-info directory
@@ -71,7 +72,7 @@ def info(directory):
     # read the package information
     pkg_info = os.path.join(egg_info, 'PKG-INFO')
     info_dict = {}
-    for line in file(pkg_info).readlines():
+    for line in open(pkg_info).readlines():
         if not line or line[0].isspace():
             continue  # XXX neglects description
         assert ':' in line
@@ -95,7 +96,7 @@ def get_dependencies(directory):
     requires = os.path.join(directory, egg_info, 'requires.txt')
     dependencies = []
     if os.path.exists(requires):
-        for line in file(requires):
+        for line in open(requires):
             line = line.strip()
             # in requires.txt file, a dependency is a non empty line
             # Also lines like [device] are sections to mark optional
@@ -180,7 +181,7 @@ def main(args=sys.argv[1:]):
     if options.list_dependencies:
         # list the package dependencies
         for package in packages:
-            print '%s: %s' % get_dependencies(os.path.join(here, package))
+            print(('%s: %s' % get_dependencies(os.path.join(here, package))))
         parser.exit()
 
     # gather dependencies
@@ -235,7 +236,7 @@ def main(args=sys.argv[1:]):
     if options.list:
         # list what will be installed
         for package in unrolled:
-            print package
+            print(package)
         parser.exit()
 
     # set up the packages for development
diff --git a/testing/mozbase/test.py b/testing/mozbase/test.py
index 013506fc64..2a329b461b 100755
--- a/testing/mozbase/test.py
+++ b/testing/mozbase/test.py
@@ -9,6 +9,7 @@ run mozbase tests from a manifest,
 by default https://github.com/mozilla/mozbase/blob/master/test-manifest.ini
 """
 
+from __future__ import print_function
 import imp
 import manifestparser
 import mozinfo
@@ -82,7 +83,7 @@ def main(args=sys.argv[1:]):
 
     if options.list_tests:
         # print test paths
-        print '\n'.join(tests)
+        print(('\n'.join(tests)))
         sys.exit(0)
 
     # create unittests
diff --git a/testing/mozbase/versioninfo.py b/testing/mozbase/versioninfo.py
index 82da432a4c..96803a4a0a 100755
--- a/testing/mozbase/versioninfo.py
+++ b/testing/mozbase/versioninfo.py
@@ -9,7 +9,8 @@ List mozbase package dependencies or generate changelogs
 from commit messages.
 """
 
-from collections import Iterable
+from __future__ import print_function
+from collections.abc import Iterable
 from distutils.version import StrictVersion
 import argparse
 import os
@@ -62,7 +63,7 @@ def changelog(args):
                         if StrictVersion(v) == plus_version:
                             return rev
 
-        print("Could not find %s revision for version %s." % (args.module, v or 'latest'))
+        print(("Could not find %s revision for version %s." % (args.module, v or 'latest')))
         sys.exit(1)
 
     from_ref = args.from_ref or get_version_rev()
@@ -83,8 +84,8 @@ def changelog(args):
         lines = [('* %s' if i == 0 else '  %s') % l for i, l in enumerate(lines)]
         return '\n'.join(lines)
 
-    changelog = map(prettify, changelog)
-    print '\n'.join(changelog)
+    changelog = list(map(prettify, changelog))
+    print('\n'.join(changelog))
 
 
 def dependencies(args):
@@ -100,8 +101,8 @@ def dependencies(args):
 
     # print package version information
     for value in info.values():
-        print '%s %s : %s' % (value['Name'], value['Version'],
-                              ', '.join(dependencies[value['Name']]))
+        print('%s %s : %s' % (value['Name'], value['Version'],
+                              ', '.join(dependencies[value['Name']])))
 
 
 def main(args=sys.argv[1:]):
diff --git a/testing/mozharness/examples/action_config_script.py b/testing/mozharness/examples/action_config_script.py
index e1135771e0..fc1cfba41c 100755
--- a/testing/mozharness/examples/action_config_script.py
+++ b/testing/mozharness/examples/action_config_script.py
@@ -4,6 +4,7 @@
 Demonstrate actions and config.
 """
 
+from __future__ import print_function
 import os
 import sys
 import time
@@ -68,11 +69,11 @@ class ActionsConfigExample(BaseScript):
             try:
                 time.sleep(interval)
             except:
-                print
+                print()
                 self.error("Impatient, are we?")
                 sys.exit(1)
             counter += interval
-        print
+        print()
         self.info("Ok, done.")
 
     def _ship1(self):
diff --git a/testing/mozharness/external_tools/clobberer.py b/testing/mozharness/external_tools/clobberer.py
index 300b2bc2f3..761ecfc6dc 100755
--- a/testing/mozharness/external_tools/clobberer.py
+++ b/testing/mozharness/external_tools/clobberer.py
@@ -1,8 +1,9 @@
 #!/usr/bin/python
+from __future__ import print_function
 import sys
 import shutil
-import urllib2
-import urllib
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 import os
 import traceback
 import time
@@ -80,7 +81,7 @@ def rmdirRecursive(dir):
         return
 
     # Verify the directory is read/write/execute for the current user
-    os.chmod(dir, 0700)
+    os.chmod(dir, 0o700)
 
     for name in os.listdir(dir):
         full_name = os.path.join(dir, name)
@@ -91,14 +92,14 @@ def rmdirRecursive(dir):
                 # I think this is now redundant, but I don't have an NT
                 # machine to test on, so I'm going to leave it in place
                 # -warner
-                os.chmod(full_name, 0600)
+                os.chmod(full_name, 0o600)
 
         if os.path.isdir(full_name):
             rmdirRecursive(full_name)
         else:
             # Don't try to chmod links
             if not os.path.islink(full_name):
-                os.chmod(full_name, 0700)
+                os.chmod(full_name, 0o700)
             os.remove(full_name)
     os.rmdir(dir)
 
@@ -107,11 +108,11 @@ def do_clobber(dir, dryrun=False, skip=None):
     try:
         for f in os.listdir(dir):
             if skip is not None and f in skip:
-                print "Skipping", f
+                print("Skipping", f)
                 continue
             clobber_path = f + clobber_suffix
             if os.path.isfile(f):
-                print "Removing", f
+                print("Removing", f)
                 if not dryrun:
                     if os.path.exists(clobber_path):
                         os.unlink(clobber_path)
@@ -122,7 +123,7 @@ def do_clobber(dir, dryrun=False, skip=None):
                         shutil.move(f, clobber_path)
                         os.unlink(clobber_path)
             elif os.path.isdir(f):
-                print "Removing %s/" % f
+                print("Removing %s/" % f)
                 if not dryrun:
                     if os.path.exists(clobber_path):
                         rmdirRecursive(clobber_path)
@@ -133,21 +134,21 @@ def do_clobber(dir, dryrun=False, skip=None):
                         shutil.move(f, clobber_path)
                         rmdirRecursive(clobber_path)
     except:
-        print "Couldn't clobber properly, bailing out."
+        print("Couldn't clobber properly, bailing out.")
         sys.exit(1)
 
 
 def getClobberDates(clobberURL, branch, buildername, builddir, slave, master):
     params = dict(branch=branch, buildername=buildername,
                   builddir=builddir, slave=slave, master=master)
-    url = "%s?%s" % (clobberURL, urllib.urlencode(params))
-    print "Checking clobber URL: %s" % url
+    url = "%s?%s" % (clobberURL, six.moves.urllib.parse.urlencode(params))
+    print("Checking clobber URL: %s" % url)
     # The timeout arg was added to urlopen() at Python 2.6
     # Deprecate this test when esr17 reaches EOL
     if sys.version_info[:2] < (2, 6):
-        data = urllib2.urlopen(url).read().strip()
+        data = six.moves.urllib.request.urlopen(url).read().strip()
     else:
-        data = urllib2.urlopen(url, timeout=30).read().strip()
+        data = six.moves.urllib.request.urlopen(url, timeout=30).read().strip()
 
     retval = {}
     try:
@@ -160,8 +161,8 @@ def getClobberDates(clobberURL, branch, buildername, builddir, slave, master):
             retval[builddir] = (builder_time, who)
         return retval
     except ValueError:
-        print "Error parsing response from server"
-        print data
+        print("Error parsing response from server")
+        print(data)
         raise
 
 if __name__ == "__main__":
@@ -196,11 +197,11 @@ if __name__ == "__main__":
     except:
         if options.verbose:
             traceback.print_exc()
-        print "Error contacting server"
+        print("Error contacting server")
         sys.exit(1)
 
     if options.verbose:
-        print "Server gave us", server_clobber_dates
+        print("Server gave us", server_clobber_dates)
 
     now = int(time.time())
 
@@ -214,7 +215,7 @@ if __name__ == "__main__":
     for builddir, (server_clobber_date, who) in server_clobber_dates.items():
         builder_dir = os.path.join(root_dir, builddir)
         if not os.path.isdir(builder_dir):
-            print "%s doesn't exist, skipping" % builder_dir
+            print("%s doesn't exist, skipping" % builder_dir)
             continue
         os.chdir(builder_dir)
 
@@ -223,8 +224,8 @@ if __name__ == "__main__":
         clobber = False
         clobberType = None
 
-        print "%s:Our last clobber date: " % builddir, ts_to_str(our_clobber_date)
-        print "%s:Server clobber date:   " % builddir, ts_to_str(server_clobber_date)
+        print("%s:Our last clobber date: " % builddir, ts_to_str(our_clobber_date))
+        print("%s:Server clobber date:   " % builddir, ts_to_str(server_clobber_date))
 
         # If we don't have a last clobber date, then this is probably a fresh build.
         # We should only do a forced server clobber if we know when our last clobber
@@ -240,9 +241,9 @@ if __name__ == "__main__":
                 # We should also update our clobber date to match the server's
                 our_clobber_date = server_clobber_date
                 if who:
-                    print "%s:Server is forcing a clobber, initiated by %s" % (builddir, who)
+                    print("%s:Server is forcing a clobber, initiated by %s" % (builddir, who))
                 else:
-                    print "%s:Server is forcing a clobber" % builddir
+                    print("%s:Server is forcing a clobber" % builddir)
 
         if not clobber:
             # Disable periodic clobbers for builders that aren't my_builddir
@@ -264,11 +265,11 @@ if __name__ == "__main__":
                 clobberType = "periodic"
                 # Update our clobber date to now
                 our_clobber_date = now
-                print "%s:More than %s seconds have passed since our last clobber" % (builddir, periodicClobberTime)
+                print("%s:More than %s seconds have passed since our last clobber" % (builddir, periodicClobberTime))
 
         if clobber:
             # Finally, perform a clobber if we're supposed to
-            print "%s:Clobbering..." % builddir
+            print("%s:Clobbering..." % builddir)
             do_clobber(builder_dir, options.dryrun, options.skip)
             write_file(our_clobber_date, "last-clobber")
 
@@ -276,4 +277,4 @@ if __name__ == "__main__":
         # Note in the case of purged clobber, we output the clobber type even though no
         # clobber was performed this time.
         if clobberType and builddir == my_builddir:
-            print "TinderboxPrint: %s clobber" % clobberType
+            print("TinderboxPrint: %s clobber" % clobberType)
diff --git a/testing/mozharness/external_tools/count_and_reboot.py b/testing/mozharness/external_tools/count_and_reboot.py
index 9e8ae35a65..643ddc2c40 100755
--- a/testing/mozharness/external_tools/count_and_reboot.py
+++ b/testing/mozharness/external_tools/count_and_reboot.py
@@ -6,6 +6,7 @@
 Increments the value in countfile, and reboots the machine once the count
 reaches or exceeds maxcount."""
 
+from __future__ import print_function
 import os, sys, time
 
 if sys.platform in ('darwin', 'linux2'):
@@ -55,8 +56,8 @@ if __name__ == '__main__':
     if increment_count(options.countfile) >= options.maxcount:
         if options.zero:
             open(options.countfile, "w").write("0\n")
-        print "************************************************************************************************"
-        print "*********** END OF RUN - NOW DOING SCHEDULED REBOOT; FOLLOWING ERROR MESSAGE EXPECTED **********"
-        print "************************************************************************************************"
+        print("************************************************************************************************")
+        print("*********** END OF RUN - NOW DOING SCHEDULED REBOOT; FOLLOWING ERROR MESSAGE EXPECTED **********")
+        print("************************************************************************************************")
         sys.stdout.flush()
         reboot()
diff --git a/testing/mozharness/external_tools/detect_repo.py b/testing/mozharness/external_tools/detect_repo.py
index 67466a03e0..fbc8024653 100644
--- a/testing/mozharness/external_tools/detect_repo.py
+++ b/testing/mozharness/external_tools/detect_repo.py
@@ -2,20 +2,20 @@
 # Stolen from taskcluster-vcs
 # https://github.com/taskcluster/taskcluster-vcs/blob/master/src/vcs/detect_remote.js
 
-from urllib2 import Request, urlopen
-from urlparse import urlsplit, urlunsplit
+from urllib.request import Request, urlopen
+from urllib.parse import urlsplit, urlunsplit
 from os.path import exists, join
 
 def first(seq):
-    return next(iter(filter(lambda x: x, seq)), '')
+    return next(iter([x for x in seq if x]), '')
 
 def all_first(*sequences):
-    return map(lambda x: first(x), sequences)
+    return [first(x) for x in sequences]
 
 # http://codereview.stackexchange.com/questions/13027/joining-url-path-components-intelligently
 # I wonder why this is not a builtin feature in Python
 def urljoin(*parts):
-    schemes, netlocs, paths, queries, fragments = zip(*(urlsplit(part) for part in parts))
+    schemes, netlocs, paths, queries, fragments = list(zip(*(urlsplit(part) for part in parts)))
     scheme, netloc, query, fragment = all_first(schemes, netlocs, queries, fragments)
     path = '/'.join(p.strip('/') for p in paths if p)
     return urlunsplit((scheme, netloc, path, query, fragment))
diff --git a/testing/mozharness/external_tools/download_file.py b/testing/mozharness/external_tools/download_file.py
index 91b0a46685..bd149fd185 100755
--- a/testing/mozharness/external_tools/download_file.py
+++ b/testing/mozharness/external_tools/download_file.py
@@ -9,17 +9,18 @@
 We lose some mozharness functionality by splitting this out, but we gain output_timeout.
 """
 
+from __future__ import print_function
 import os
 import socket
 import sys
-import urllib2
-import urlparse
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.parse
 
 
 def download_file(url, file_name):
     try:
         f_length = None
-        f = urllib2.urlopen(url, timeout=30)
+        f = six.moves.urllib.request.urlopen(url, timeout=30)
         if f.info().get('content-length') is not None:
             f_length = int(f.info()['content-length'])
             got_length = 0
@@ -28,42 +29,42 @@ def download_file(url, file_name):
             block = f.read(1024 ** 2)
             if not block:
                 if f_length is not None and got_length != f_length:
-                    raise urllib2.URLError("Download incomplete; content-length was %d, but only received %d" % (f_length, got_length))
+                    raise six.moves.urllib.error.URLError("Download incomplete; content-length was %d, but only received %d" % (f_length, got_length))
                 break
             local_file.write(block)
             if f_length is not None:
                 got_length += len(block)
         local_file.close()
-        print "%s downloaded to %s" % (url, file_name)
-    except urllib2.HTTPError, e:
-        print "Warning: Server returned status %s %s for %s" % (str(e.code), str(e), url)
+        print("%s downloaded to %s" % (url, file_name))
+    except six.moves.urllib.error.HTTPError as e:
+        print("Warning: Server returned status %s %s for %s" % (str(e.code), str(e), url))
         raise
-    except urllib2.URLError, e:
-        print "URL Error: %s" % url
-        remote_host = urlparse.urlsplit(url)[1]
+    except six.moves.urllib.error.URLError as e:
+        print("URL Error: %s" % url)
+        remote_host = six.moves.urllib.parse.urlsplit(url)[1]
         if remote_host:
             os.system("nslookup %s" % remote_host)
         raise
-    except socket.timeout, e:
-        print "Timed out accessing %s: %s" % (url, str(e))
+    except socket.timeout as e:
+        print("Timed out accessing %s: %s" % (url, str(e)))
         raise
-    except socket.error, e:
-        print "Socket error when accessing %s: %s" % (url, str(e))
+    except socket.error as e:
+        print("Socket error when accessing %s: %s" % (url, str(e)))
         raise
 
 if __name__ == '__main__':
     if len(sys.argv) != 3:
         if len(sys.argv) != 2:
-            print "Usage: download_file.py URL [FILENAME]"
+            print("Usage: download_file.py URL [FILENAME]")
             sys.exit(-1)
-        parts = urlparse.urlparse(sys.argv[1])
+        parts = six.moves.urllib.parse.urlparse(sys.argv[1])
         file_name = parts[2].split('/')[-1]
     else:
         file_name = sys.argv[2]
     if os.path.exists(file_name):
-        print "%s exists; removing" % file_name
+        print("%s exists; removing" % file_name)
         os.remove(file_name)
     if os.path.exists(file_name):
-        print "%s still exists; exiting"
+        print("%s still exists; exiting")
         sys.exit(-1)
     download_file(sys.argv[1], file_name)
diff --git a/testing/mozharness/external_tools/extract_and_run_command.py b/testing/mozharness/external_tools/extract_and_run_command.py
index ab48ee1dff..828f95cca7 100644
--- a/testing/mozharness/external_tools/extract_and_run_command.py
+++ b/testing/mozharness/external_tools/extract_and_run_command.py
@@ -20,7 +20,7 @@ import logging
 import os
 from os import path
 import sys
-from Queue import Queue
+from queue import Queue
 import shutil
 import subprocess
 import tempfile
@@ -75,7 +75,7 @@ def find_files(d):
             yield path.abspath(path.join(root, f))
 
 
-def rchmod(d, mode=0755):
+def rchmod(d, mode=0o755):
     """chmods everything in `d' to `mode', including `d' itself"""
     os.chmod(d, mode)
     for root, dirs, files in os.walk(d):
@@ -90,7 +90,7 @@ def maybe_extract(filename):
        directory and chmods it. The consumer is responsible for removing
        the extracted files, if desired."""
     ext = path.splitext(filename)[1]
-    if ext not in EXTRACTORS.keys():
+    if ext not in list(EXTRACTORS.keys()):
         return None
     # Append the full filepath to the tempdir
     tempdir_root = tempfile.mkdtemp()
diff --git a/testing/mozharness/external_tools/gittool.py b/testing/mozharness/external_tools/gittool.py
index 520aeaf38e..1324f39c43 100755
--- a/testing/mozharness/external_tools/gittool.py
+++ b/testing/mozharness/external_tools/gittool.py
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 ### Compressed module sources ###
+from __future__ import print_function
 module_sources = [('util', 'eJxlkMEKgzAQRO/5isWTQhFaSg8Ff6LnQknM2ixoItmov1+T2FLb3DY7mZkXGkbnAxjJpiclKI+K\nrOSWSAihsQM28sjBk32WXF0FrKe4YZi8hWAwrZMDuC5fJC1wkaQ+K7eIOqpXm1rTEzmU1ZahLuc/\ncwYlGS9nQNs6jfoACwUDQVIf/RdDAXmULYK0Gpo1aXAz6l3sG6VWJ/nIdjHdx45jWTR3W3xVSKTT\n8NuEE9a+DMzomZz9QOencdyDJ7LvH6zEC9SEeBQ=\n'), ('util.file', 'eJzNVk2P2zYQvftXTF0sLC9ctTbaSwAfim2BFCjSIsktCLy0SFnMSqRAUuv1v+8MP0RZ3uTQU3Sw\nJXLmcWbem5GWy+Vb0fbCQD2oykmtLDgNDVO8FVBL/NG4y/zOcrlcyK7XxkGrTyepTulR23Rnm8HJ\nNj01zDatPKZHJ7qeMBe10R08aFXL07/MWDw+Wrxn5+nyAs+BfTqtPAn3N94KUxwOinXicFgvFgsu\naqh01zMjCkLfbnzgu/WbBeCFUcddTK0RaKqcUM6CrsGdtbe1G+iZtYKDVCAkmhlg1rvjhRVQoRah\nLuiK21UlrJXHVKaeucaW8IfGbQYW88E8I4Bi8lmAdQaTiKFKq9UGrAauQWkHg8VKK2iZOREZFBOV\nm7xlDdJKZR1T1ZjhkVkRAGOadPk9rBcFnAxXZrWBj2YQ66+A7b4BtpuC7W7A/BGHsaD7sFAawXiR\nLXZzi93Uwgg3GHUDtZ+5Rp65NKJy2lxQJY5hHsW4gtUc6lq+ZNrhfcB2GDAlTuyfkAmVYbwaCMdv\n9kY/S44qOMuWV8xwjxRgN8SpRH6oPx5bC7XWP98fmXmERFQjHWbI1KX4VJdCcXtGJRUxKrRHXklf\n2pattA5jyMGvP4/0kBoQKROB6i+FMdoUywc9tNxb1FJxuL+zBHhnl3AHRYozg15VGDHHZukvVN3C\nmgrNrdv4pU5zsffkjhV8wGVAK8rZ2/XYRcI8k45xLHQSO4BGBrYFONmh9GU9YqHQvFZSecJoKG9O\nHzNPjjn1iQttzFxmFqhpN7EIudqGbe3QFXVOKqkCCf/w9veftn5K+Wkwmw6+rx/rxw0VuREvRGHH\n3Eg3kh0HXEnHJMn3Y9NQwxxXYfncEBrVI6d3bHX1RE3Rh474bbuDe9j+svs1JxgV4U2zp/dGn6dx\npSmHnjMnCm95zXyJwXN5wh4vxrqwWhwG1Ur15JubxmkuUdiAtAHypLRRxLoXok3d5CvEceSplQPx\ngqpOxXHm8maaA4qeJmQpLel+duI4crBFjNbOa9iGMW5jy5xZmyPdoCB7rs9qqtc5km82D3G7n4mK\ncX3RUhXh7Hr9qvlVxfpbG0QyHSVHKHlbtFZcnz+phi+Z/Vo5IuqcJW8jXirRO/jnw59EyAYmZ/wI\nfxFdApbvNA6vqonvcZMnw3JKjaDpojTN3N11AEE/30jFMGnFVFGz5kbFZVGRQXvxXT7OFDTAVx8J\ni/mvA20YDmWJPWg6wSXqOcyWBoe2ofTpo4PwonOSW81REl3vxbofvzPK7snSPc3Zfao53pNZ4YNb\nvzaZ9PFL4RvYJ+FbeENE1Dy0NZ61OuPijXOeQDGWYEHK8NQVcTlWJhau1YzTew6/euZKCKuY0ey7\nqJjMTFoN4+NT8v68hh/2kB8zaXEivNNKTCdEQInx4FdWCif84atP+G9DrEIf/tGODW0iN8eB8/AQ\njYv4v/YMTvYDRjHDXN8EGV0wnBvbaewxlJvgD6ii7yUBCuV/5XDUuv1ekqBYBLt1eS2R/wBE3uXX\n'), ('util.commands', 'eJzdWW1v2zgS/u5fwXPQs9x1laDFvSBA9pDdJnfBtkkucS9XtIEgS+OYG4n0kVRc76+/GZKSKPkl\n2T3slzPQOhLJ4bw888yQHg6H55XIDJdCs7lUTFVCcPHAMlmWqcj1cDgc8HIplWG6mi2VzEDr+o1s\n/jK8hPrvZZEaFFXWz4V8eECRA/xmJ/VT/ADmA/4JKkoSkZaQJOPBwKj18YDhxy9dcfHu7ZwXsPEy\nXXL77vrz3cXlu7coeKoqGMC3DJaGXdiZZ0pJddybdp4WGgaDQQ5z0iXJyjzCfxP2+vXjKlUPeuxW\nHLBslTOumV5CxtOCccHMIsXtgaXFKl1rtkqFYRwNVlwYQBHwBILxOb4baSak8YLg27LgGTfFmmUL\nqUHY92431Mj9EWdyuY7GztA5G+HuI5JB+7oZTq926Rc75x4lSE3uxCe/Hu2KuZjLaOjDeMxup6c3\n0+HO4Vd6yF4FEY4Lrs1b9EvBBZB/xm4pQeQR1hP2lBYVtLrF3IDCf6WOxq2eWzeym02cFG1UZCWh\neBeSEtQDJCCeIvznRQlY0RtnKP7BlRShu/x4XC3z1IBdaN8rMJUS9bDfAAG+M+YI9ptKMBxiUcrI\nBUzOGU6oShBGj2PGblKuIXTUj2lRQH7tniziMHxWmllAnUYIAW4QMNwsMKbizS+gJAq7mHcmOX0R\ncVVGwuZVUawnoSVHMaWj9+wWKzze7oA5V6B0BHA6x9jUecdmkKUVmoAwzqUYGYdiNIJMJW24WNhQ\n5jV60fNPqdKsrHKCwwMKtxNlZZaVaQCL80b7wErjBNY2wp0Rp3xDAPYBZxOxxPSfj/UOWDldjoft\nJO+yIFLZArLHJENTt7nNM8feyG5B9qhR4ezm5upmNCFBCQ2dECEF+hBwXA5xgZIDO6FIlxryrrXs\nDTP7LD67fM+iV/Hbua7Xj78KzKv6IYD7fyoOZifoc3gSiDTKriWICFPMv5mw0WrUyaQ9ztQmxxic\nNEvxGZRqn1tnt3opKKWBVjEN6gnUhCE8FZWEk0spAF/rxU+wbh9ORvjfaNI4J/j0TEOpyVLBnH9D\n677gqvsarfUWbRDauTF8MyDy6MvoTTFqtblvuNkp9MxSjkvRl8vULPDtEmNGgiK3duyFBSvT5ZJW\nOh80W3HNhTapyMC5aJZqQNLELBx39if78Os+jFbAdLUXvmM95Hc4MVli4sucZ8lS1nHFedQPJFTh\nFFL1ybujowmj8fbVUfz2T1vD4T+1DELLLM0efSh/JfkSt6QBBBlRpoUhI27FxFgWQI2MlVabQpn2\nYtrepGwr67fQdkvZg20uYHPfdaFwzL0ZSrMKub1I+hxdLFdEt40LvIYOOW5z7DPgG2SVFWXSR9DI\nFQK7KpooNqLXYgZBpUxCVNNQBoYV3VHH4v+6zDxbQcgTKCQAzLVlxy2OaD25pVwVqUbmtSA9CWYO\nHCgW2NnavrU1Q9G2tGdsc3A8aEbQeBzktrFklEHHnZQjk3KYVQ/R0KPaQxBBZRsulY07C5y8kxN2\ndLyRu7sqUmBBf8lvKVF9GXXOdAYA+/VNDdXzCR2pbEJ0EvhQyNWOngK9QYNvwoh9vyd/6HOACmsw\n4RIjWfokeY6nhrQs7UHKZ3w3WCEscN+ewbXznUY7nI4a91ll000BKshBpNBOKqLGPHqlx3gS2EPm\nUX/9JFBwvBnTTkcXfvpyop2UtCnUN2tn9otU37oDGQ8WCdZ4a6zFTY61w8vAxRPGH4SkmhrH8XBf\nIfNbb2vv7NBWpJIW3lbUoykuNWljQiNvU2Aa4k7FcK8Swz4sMcvy8TNrJvWeWyDwzNJbCgw5zRBE\nmuDgA+U2HRyjvkbPefH5T4CG/1lWTTgBE1gO0AXAMuo0M3VLhOfpxJUEx/lcZEWVQ+L7WnuLMKHS\nZhIMcP38a1uatn0ISp3rMLobuvKHPQaYurduOgc/M3c3FLUU7D7xQa2IJrlpJmvcGFmqPaASbSps\nI7xQbC4hLWPnqDsXVXfvsZYV0wtZFTmVc6rttuw3jQxSX5Yu0RbANq1AI/G7lJUgm600pxeLvsfx\nOaxwuaw0eWC2NqDHk0bNHNK8kNljc9rlfXeEfYxVu1Oqb6fvrz5N3amuk5LNZCqfg+c6nN/nUOu9\ncMKGbdbtOuju7UL8iSscvLg+a05e7uv53OnaXO+KjMVNoEmjtR10W8eIlLxbQu2oA3Qmc2B/2Ogu\nXlK3e1J8EQ+2oQ6oTr3NLujZq4HORDe8cW8QdJ0vuRlAUmwVOWAfsRPHBQpc6njvufxl0qVpU7za\ne4C4cXOwfeu13+X6YP/tAZ7QnyChQ2xE/7W8NqXcp64f5yyLNANiNHs9qBdYZIpYlcgk3v6VVI8a\n2cfQCaESCEx/rhK5XOmYTbHk4QRkkB8gVVhnrIOubk/PrUR32MrBHaWiHyR6fIUGz5Us2aziRT6T\nBsk8fYK4vrceB0eYugO6IWuIz2w/bO0Z1JmecJ14fbbfYH7StDJxZtVTGXUMLXZ6o85lPWQ1OxKI\n2wsCrA06dLHDkfUyOicv8GA3U/IRz3TYxD3qMBtqIVzTUF8IfXCGi+R+jfYLeomQA/YvPNTN1zZk\nOVeQGanWhBPiisMVHfgOXR8CbWgrpQg8dD8y8Dtli1LmdqMJO/rL0ZEPFC2huxiiZOkuqXGXvqZ0\nAre/KbgbY2vTz5ILL49GxoGTMR/vXMAmtqmuT6wLxBOzKtNtQsm1tud1qpk07JwRyLGndjzRHbaG\nA6cajJwsmS/yxAaiFz2n6gkbCTPqBq6FSWrvFqLGNHu5dJdc/TTe7DgP2AXVZvHoKrQ9Mq5Q3xxT\nD0/hE8wZg1MCK7EdvpxukVOmGcoBykws0aS6teViVLIHaTsDyQogCdz+UGGZYIucN9Qf+uj2gOki\nHdh19Ocm3Bu4pGA3U3uWh1zVzglYst+cH7D31gNYnm3zQor0sqsbgzA5dmmx0yoL4t4sn089bWmg\nbGCNTHwQspPtGfs0RDc/AudZRizlLwtyt9aOxLdQm15rAyWVc/9bXezetL8/+RkY02joswM5c/iR\nZ0pqOTfDwG5fMu0PcJ3lsW3iNd1p4dHn89/vLi6fWbczG8K53qxtZNvUpzql39if7+Y8Y2FBqimV\n1iCAxYNZ6PD8xT6e/ju5Pp3+I24UuJb2DGQ9nBVyNgMFKl6u486FWaqRxEzX5e5CiXZq6QjpsGir\nquM2QoGfNvqKn799/Tpi39mVe2pGs2zDseEi//vncZhWXVRv4dHA7/Vd8iiHgh2es8N/siFW0RGe\n/brVYDPN+hIsttnh7XYZYe/UKSBExOnM/xLc/C4c34I5x+9TYxRHWgN9F/WdNwmmn198OEtOp9Ob\nix8+Tc+Sy6ubj6cf6p1v8ZABjuDxFOLwgp2UvZJNLbUT+5VAHZbeFhLnxf7+m4hv9XkPBRggCzaX\ntSVvPkdHUC7WP33H5wguWqU3luEXvnodvx6FFRGnJin6CLFlhX05um8vxVyldO//et+BSJ2L8YjV\npdc+xr1ClWE3zkXVcv+LanC4VaviH3fH6/3FzdmP06ubz93d+1TwIvp/MYYCFn8RkDY32BHlnprt\nfNuowvsa/lug8V+mJBic\n'), ('util.retry', 'eJytVk2P2zYQvetXDFwsLDuC4C2wORhxsUHQFgWKnHqXaYmyiUqkQ1LxGkX/e2dIivpy0h6qw1oa\nDh9nHt/MjmivSluwouVJrVULdSdLq1RjQPilm2ZX49dKJS1/s4049YvB0jLJzlwnwdqo81nIc4K/\ncOi/8jO3v+Mr12lRSNbyotgkSVLxGjS3+p6y0golM2DW8vZqzeElA9NwfqXgDu93GbTsrRgsL7AF\ntCYQH4dT8LeSPJQ0h/Tn/j3bZFA2nMnuevisJMdj9Bkd0Pznzb3+9fdm77BWq9Un1jRw9AGtgdHB\nou1aUDVaQ3hrR5qBTlrRgLBgurLkvDJDRJgb6xqLyYNV8JLDMUa/BmHAXjjIrj1xTciGI5uVIdcb\nEzainLi9cS4jL9kM9/0OmKygUt2pIRNn5cVT0W/J0C3CTbOZULrOAY5zEl2kDGx3bThuiTiRWsqD\nYfoX1TUVRgsl684Xm8NvNQwwoDBbTa4S/yjDI1AjjOUVCPnobKY5aCYMOjgJ9peSEXl3uAm8qNOA\nFVxF2/JKMMubuwvjGK7e5XLV6quo0ItYK/Gm2QkzwwsksBHrbm0KBqy2mASmELMnxD7hz4pU1bVc\nWhOBQohwZYZCwwsTnpu76nSvSV92BKf5l05o1NUSCUPEwzTKBCOSlIEjHnFckbp1ScH1WxtuTETO\nI86R9L526R+9+D3P/SU7NYnSkkBiFBQ4pQBY8YOY0HjsKVxj4bgFSpR6Q7CHwt6M16SyMXWlB9dg\n876inlY8fBj6wX6QjzrnFT9153Q19X6qwBHgJDc2r+AJ0lHbgOkxo66z8YFI7GLP7u12EUiQhA+H\nWI5DJKjd/QSWQhOyVunKCXsP1FeoRJ8MysJeXA/a41ffhPz7agISn1U4EX4IKfQN01id0u6Nf/VQ\n+CFD+LE4uO00qsNtS7fklcF2G/yjqy+/RTNdphZYj7lREQwVv4dVRl8FMXD4Q3d8Gg3ebrjt/SLf\nsJAuduBNPGL+m4T/Kr4S36QyidwSbWM1Ttih1jE/b5DNT7D7D+f9wlAfVVCQu+kq9vUTrxV1M/LE\nJYzl8T3TMyhw4UPW3K2n3/EaAj+M3rfw48JzluWkFJYZz7En7hNvGg2E7AZjLSTKf1YiEt5RbQ1z\ngHB9YOvV10vUfwWheoD1eg0f8T9hqTSz2EKQ2zBHbHLszqylTtYZHEu8/+sA7tmiA2ulRhrL8zyZ\n+8Zh5Hm3G48jz7sB5cR0utlPYEKESfQpImRRowIVxkmNebTt1Q1a3jqeIMZbyeWKA9S8dveP6tyz\nQXhh2PGbwrjjfxBjxPS39Ti7gmR21DLE5PFqyB3v+3U2OsY5EEsjBP3vIlhwFlEKYb/D0v/M0CN2\n7oLjNNTHkvwDPQB6iA==\n'), ('util.git', 'eJzNW+uT27YR/66/ApF7IymWeEk/Xuam4/iReJrGntiZdMZ2JEoEJcQUIRPgyddM/vfuAyDAh+S7\nNkmrGVsiCSx2F7u/fRA3Ho+f1eXGKl0aketKqNLKKoUb5VYcld2J3XY8Ho/U/qArK7Txv0y9PlR6\nI01zp66KQ1oZGV0Xau2vKjka5ZXei9qqItno/T4tMyP807pcbvbZHIbt9Y1cHlK7m9PdD7WSFp9F\ns3NVSD/TpLlc1mWhyvcjv1aht1vgfwTf4tpfJVtpv4Ofspoul2W6l8vlbDQabYrUGPFE5mld2Fe7\ntJJfp0ZejQR8DvBo1H0EFLu3pkgok7lY7tP3cpmujS5qK6eVPOgZk1K5wKvE2LSyBhU7HaMYV5eX\nYzcEPw/EP4CCcE9QhUZ4cs0gVA5wgfTeFLKMCb1rBuFTGOSfXZixuIDtS3ByAiTxe4r/zWiKLIDD\nMRIRpbZgBUTgqkuuS4AkHPEAW1c8yykD9L3ES1J2rIu1sgZoeXtJUMpDoWxEbaeN5SFgQsmHWoM2\ncVpSSlvozVyMx7NRpIv+QGKzMLZSh+kYVBOmOE69KL9oVU5xvblgdTD3u9QA9zfKgGdMM4mP/aUT\nA9ziByJlxOuqlrzFPELIj8qAkKBGnIoOhDNsdRtpNDbu6ZvJVtnJXEzAWvFrsdAl7Ekp6aL8chKW\nfzcXm2N2jYRn0f6QUMgI7+fHjTzEXpo8TotCZi/56mlV6eqqO/tZWoD7xvLnjeg57uI5yWlAR/DE\nKZyfbdJSrKVIxbpKy81OANrYdCvwWXIfFZmdPi6AKKkmmzTc/TmKUSVYKmtlDf5/Tc+CYp7DY5UW\n6l8SPBcMYX+wt+QVRlld3YrUsmbE85x+eI0BGgplyonlKXOhLOBvUaDGGBQz1ibMW+HCKxhOYs2F\n3ckS1Qp32VH9xE0lUwsTvXZho9C7vekrk6mKZIkgCAwwUWWup2NaFuMAgMdctNUawe40PJGFh078\nYDhBfeF6BQg5sBgNi3CFnJGVm89ao06x1RkGEralyzur8a42QWbamd+WYEhamEDPH4hv/BbloOb3\nQtcWl4ebADqw+1Y7/XNM3ctM4QUwJTdgCjgENORoscxoBLSZ8N8tW0YifmLP2SHhHez5EQccagA8\n0AFodw+hSB0K3nrj6MF9AFe07AIZMRiqMjYOFBu424ElbnRpUxiK4VjTDFnamENH7TtpJ8ZLA0SR\nv7YgqjK278CwFRgRYaSJrYRd8MUrcra5iBQO+pOJrKoSgs21+OsX7a14IL4H602blUFFSCFJEgBL\noXNii4UweEn+xU6Vdgg1JFr3q1ShnztO0J8CAwBBYKgNCCEMMFDjMPr1YcJe8m7AF07NDnNGbSsX\nY3YGmDhzcauFhnjfI5JZAlmKtbF/DaC0Uwio8AYgKhMwjWziPvjQhsTeliOqgqQRvr7UB0hS3oxh\nMfBXcN+bBcV9vFgs4O4CVhlH4D0XgBXgTdcxkecvn85iM8EHyTEFLJ6Jz65Fx1JaTDbWWNtDjWkF\nzeU1ErDpbDpLOFEIK6BCga0Imkpd7QkxBrCKKc9aUQc0DLOnDaFr1j5gYnRrgNY4QUXNehGMSf4+\nMQxTM8fFCYthT4LcCsADf6OlBLdDZOco9gx+NXHHMEAphg02Nmtkkc9pRiW3dZFW7aE07JJkdkYI\nSbesbN+qRwN+BACWK5cwrbUu+BeIxw8rmZB3skeeMk0qPO5mfJHVscOYJUn/SZtSeRiLWTluxjjs\nUTYcA50tDOAJTsAxscY8Ac4oplkr3c3c1hvYeooGlG3POTK4/U8LiFMlYLzpshMbDGXpoF69/gXM\nwTCc5Rq/A4EJL07Ul27kOaLMRkTVRVkqQWmXAm0YdZzMQGqRR8lGcqwUJP/jC/O2xFqntbSHyk0h\n0zKuRR6I10cNNpNDfNvDMyPGNAatZK+zupCYZBx3CvJVir0QNY9SHFOIk0aLPK2SBpxbSSpRIXPM\no/+zicM5p/wTpsbMplm2xFTF+r3iC6qnmotIFnCgR1mG6M7PKLPOxCqatvL+DEUU4JPHf0wXVvhj\nxVYOu0MNABi8itZZeRftScuDyAQyzsiHOY2kn0UG6UZAFXdnSV9JyygFkwhdvNR34BGWXMC0+/G5\nbfjs8ziMn54zxs8bWbopcwwC32PKojhlcduVaYm5ioN4FerGDugFQRY3d4W28/Y2BG3IORaglEp2\nwA3vm2mUFOypHwHJnt3sphX6oHk4ffvq4Uy8neYSbr6d/QWdEsZIs0kPqMOgvTkt1Arv+8F4vk+2\nla4P0y/7xnM/wznvIIM2j6lZJtf1FiHmCs2BXISHIkiE7sX+1jEFWjlrNj40RBOuY667QXzUnwCg\nhCkbmtNQDYesmharUDahjPD/9AgQemFmjvfTypuH9aIK8F5+OxDC2kwCbrR5vDCf5Cswc3eo9N7s\n2k1z0WpwXKMeQ6vFXdaHDOLOEkdeU8UdlOBbgNfdniDoTGEeZhwNigdMotMxwI6fAdeF1ICKshUO\noup+B/uz8rysEDVWjs+V2OzkBiorqjqxM0rUGMMTNpMnmsMV1o20BOw6VmO8yi49AEDMwbs3RU2q\nh6TMqHVxC6zq9VpW2EGlVIMaOU3vwYlFDIINzLkEttjagOq1NpIgzY0Sawk4IhvGnMiNHTf6Q2rD\nTdiWmjmFkOWNqnSJHd3p+Jvnr5evvn30w9Pl149ePV0+ef4D2A3qfDa8St9bmiZl466tpmWbi05V\nQImMCZvezB2y+JgAstBmkB5EDJI+qRkbZcLNyMGODVXouJehFURuFGY1k1pFG7GBfa1moGtuobW3\nGyQgeG0V6CYaytr2I1x18pS+wHDbyyCzx7QqgUvgV9dFhuW5ay3EbYoL8xVUHCZdU58Dn8B3LMsc\nV1qi4ANsxhZDqu497O0D1Sv9FjfXHp3q/DF6H/JFkzr9MVdFnyjL3Yhust7vi7U0BYDo0gOBjgtV\nFHgzNVNDJd/UZ19FLtzr3LHFhwZYJN85a+x2YkKf06UwsGVosAAJgJd0j+j0bazPTqhJXAXWN9d+\nX+6BeAGLVEcFewziUqICOmmKIv+hZ4NY774DUrvvNuAzWvueH72eIazWdcWMopbijJnUobY7Kw5F\nupFnfTx24s37Jb3Y+lSVRIqB2lCVmfyY4Lzx7IxlNYQHzGuooRrGt/coaoEODDmzhU5zEDuOEnJX\n0N4BQg24OVsw6dqpLm0i75wDHMpzlI7CLr1xwat5z5IWmI7eUjfd6HnTPIWaH5UsSknrOAKUiYKV\n3todvhBkr9dLvn0ddYviVzmwW+2deoAFYKbRFYmjwLQwB7lRuZKQdENxiD1azJ7ljax4yVC+h1XD\nmwl8Bdd97dJ648Srx5ylG1unBcRsZCIXbM6wNHDoRMc6iAWPSPhMgAz56PbAO3L+aS7RfD/9gmxI\nWdT1CZtsmi1ym6PsydX9zvj7V4OY1QWJZ0QCnRUkM4wRjeu2xvYiIhN4/eLJiyvxLWAb+CYtzHkq\nYYeByuU9Kc1c2nRrLv8Jnx6R6P1Yz5riD1GP+zIc5jrwNOvNHX5pcXeKPUjsvBO5V7sxaO6V3ksy\ne7CB0oojpGzbzwbGPeZgFSEkBpJKLrgd350QgIu6/2FPaG8hUC7a4W8gmvhPHAfPDQuvBfxn0Fju\nt8/Rfrg3XnjblTHXYw0xRJXj++/23ej+IXseZaLNDpzMQO+5Cffd9n6a0V3sxIj2Zve1Pbj1saOx\n1v8jHzuRNP+P5AcXhmyOsRONh1u6oaHBgk7Yoia+A+JxOkqihmqVH33c51bkRh9uvYquKPn3UeLK\ntwJyX827KBMFGYIahXgcOSAe34HYAhE4NVGUjsNGs0Y7Tf10hCOIagdrp4fLCzOhTlcvFg7owLCD\nIIM+fgO/xkJSgy8wPZHxkNRhS3NXvPYkDENcyhDXO+4Bnp6hnZqeyI6bZkifBZVHfY22oNxpHzyL\nAXQaIxmaHk/1bftTOTw3V9qtFq4iOXHvN29C4+UxUjWhCY5bSim7wZ5J04khu4bbFMgg+8R0jmDB\nv+iifDMR4jWkT0ddUV1I5uyPYdCJjju3ULiYodNu/U4K94NhBC5CY1o9H6TO4nePh6CUUXltGuZq\n8JEwOdIWUXBKJBKQTw+K506ZNM0dt7XnK9wTJSj2NlngIcx4ZC3q0lULkaLcnChaYvua79IZiS7N\nNt3HsUIJbXhC29kGgb9508s2yvM6Vto2wuj3kDN3X/b6j4sQf5e3a51W2XM8U1LVBzvAUi9tult0\nkf7xdAxhfl3IfdvSnDpP6gc/eKJElXVYvh8/g9pfukMs8RaKPIXCMvsKvvnhOoUy0OrQD3aW0n0T\njOp3RyrexW2YwTDk0/ofwYv5BMflYuHkQ2/+WwCjfZZQqzSbThaLUi+oLtW1nQSL9WGrNUl+tDjp\nDb6ZpvNu0UG1TmsyuzqxHD+dBIkbqgEL34XTIc25EEd8UHRnYdzojIKbx9rBYDDYFo967CFdbdCV\n4jtAaQsyXG+b37G4Tja3tV2TOyEYKqVCUPUAiz0lX9kPQxAznTVvN3HlqE2gaSorsa7okJNbHtb7\njvOPXVpuZYDFTJkNuFl0eM61MLpFP8Sbo8Iak9ZOrRv7EyFrM+rnL8SUqxpaFi7XstDHGVW+utpw\n8c0lJfVFHJkMjDGHf+WGMhlEPb3fA5arzPj30nvq7iPAc88EKO35NFrpzj0hHZvC00wYC7pJIFbx\n6Qv5oVaANKgRoD1piOD0xYJnTeYeQJQ/EEY9nAo1vr4VugAuBURFQ6fINb1dGeqj9LteXSf2vuWP\nRvF784bGQzH5+YtJdMg5GH337GcbdxwW9ByVHcLnT5MLc7lPIfuqOINrzPsMmrVnc+437bx96uT7\ndxWaCXuZ7yL0p3y7X6V0Hbzv0Z36cSjh4gHY/+hkWNR8Adv0zkVAfyLfwiMIhA53TpS4O9RLlOgs\nYpwuuQwpfu/UywfukC6cCv+ocVbsYPA/W+/9udG8KRn/D8P5A/FYlzeycraBzeCy+dMHPopGh2sn\nWMpxyRhOVTvjpz9RGPobjKGEgZTR+Bwd+ojThmDTcdbwhDqZbHj4LPQTmSXqAXKnEUq7jWziBebO\n6a1vRTMxKE/1RnHjVUOsoLNOrkFKb8GpGkhxxUNdbSV6CUY2d+TIydTOTpCBySyAbwfvVN7y5k7J\nFoiNH1JL0x1uuPw1nvTb5a+O7m9X7VERfESDxgk41z7F9+29yjLATQsyW4gTX0THIvuW2Od/B3W0\n+aPZnZ0IOL+Doj8/x/HnEad/ih7/O25mztFPhK/4kJWLXPTnOL2TVZzzNClBOJS6wvErn+AVt3R8\nIjom0SRyJ48ohwNW7ogyXnz79NETf2qP/yztPqeoXHw4czr03yOfFDU=\n')]
 
 ### Load the compressed module sources ###
@@ -7,7 +8,7 @@ import sys, imp
 for name, source in module_sources:
     source = source.decode("base64").decode("zlib")
     mod = imp.new_module(name)
-    exec source in mod.__dict__
+    exec(source, mod.__dict__)
     sys.modules[name] = mod
 
 ### Original script follows ###
@@ -91,4 +92,4 @@ if __name__ == '__main__':
                        clean_dest=options.clean,
                        )
 
-    print "Got revision %s" % got_revision
+    print("Got revision %s" % got_revision)
diff --git a/testing/mozharness/external_tools/mouse_and_screen_resolution.py b/testing/mozharness/external_tools/mouse_and_screen_resolution.py
index 29e46e1bc0..63835e8bc4 100755
--- a/testing/mozharness/external_tools/mouse_and_screen_resolution.py
+++ b/testing/mozharness/external_tools/mouse_and_screen_resolution.py
@@ -9,6 +9,7 @@
 # Author(s):     Zambrano Gasparnian, Armen <armenzg@mozilla.com>
 # Target:        Python 2.5 or newer
 #
+from __future__ import print_function
 from optparse import OptionParser
 from ctypes import windll, Structure, c_ulong, byref
 try:
@@ -17,7 +18,7 @@ except:
     import simplejson as json
 import os
 import sys
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import socket
 import platform
 import time
@@ -28,15 +29,15 @@ default_mouse_position = {"x": 1010, "y": 10}
 def wfetch(url, retries=5):
     while True:
         try:
-            return urllib2.urlopen(url, timeout=30).read()
-        except urllib2.HTTPError, e:
-            print("Failed to fetch '%s': %s" % (url, str(e)))
-        except urllib2.URLError, e:
-            print("Failed to fetch '%s': %s" % (url, str(e)))
-        except socket.timeout, e:
-            print("Time out accessing %s: %s" % (url, str(e)))
-        except socket.error, e:
-            print("Socket error when accessing %s: %s" % (url, str(e)))
+            return six.moves.urllib.request.urlopen(url, timeout=30).read()
+        except six.moves.urllib.error.HTTPError as e:
+            print(("Failed to fetch '%s': %s" % (url, str(e))))
+        except six.moves.urllib.error.URLError as e:
+            print(("Failed to fetch '%s': %s" % (url, str(e))))
+        except socket.timeout as e:
+            print(("Time out accessing %s: %s" % (url, str(e))))
+        except socket.error as e:
+            print(("Socket error when accessing %s: %s" % (url, str(e))))
         if retries < 0:
             raise Exception("Could not fetch url '%s'" % url)
         retries -= 1
@@ -47,7 +48,7 @@ def main():
 
     if not (platform.version().startswith('6.1.760') and not 'PROGRAMFILES(X86)' in os.environ):
         # We only want to run this for Windows 7 32-bit
-        print "INFO: This script was written to be used with Windows 7 32-bit machines."
+        print("INFO: This script was written to be used with Windows 7 32-bit machines.")
         return 0
 
     parser = OptionParser()
@@ -61,7 +62,7 @@ def main():
 
     if (options.configuration_url == None and
         options.configuration_file == None):
-        print "You must specify --configuration-url or --configuration-file."
+        print("You must specify --configuration-url or --configuration-file.")
         return 1
 
     if options.configuration_file:
@@ -74,42 +75,42 @@ def main():
             conf_dict = json.loads(wfetch(options.configuration_url))
             new_screen_resolution = conf_dict["win7"]["screen_resolution"]
             new_mouse_position = conf_dict["win7"]["mouse_position"]
-        except urllib2.HTTPError, e:
-            print "This branch does not seem to have the configuration file %s" % str(e)
-            print "Let's fail over to 1024x768."
+        except six.moves.urllib.error.HTTPError as e:
+            print("This branch does not seem to have the configuration file %s" % str(e))
+            print("Let's fail over to 1024x768.")
             new_screen_resolution = default_screen_resolution
             new_mouse_position = default_mouse_position
-        except urllib2.URLError, e:
-            print "INFRA-ERROR: We couldn't reach hg.mozilla.org: %s" % str(e)
+        except six.moves.urllib.error.URLError as e:
+            print("INFRA-ERROR: We couldn't reach hg.mozilla.org: %s" % str(e))
             return 1
-        except Exception, e:
-            print "ERROR: We were not expecting any more exceptions: %s" % str(e)
+        except Exception as e:
+            print("ERROR: We were not expecting any more exceptions: %s" % str(e))
             return 1
 
     current_screen_resolution = queryScreenResolution()
-    print "Screen resolution (current): (%(x)s, %(y)s)" % (current_screen_resolution)
+    print("Screen resolution (current): (%(x)s, %(y)s)" % (current_screen_resolution))
 
     if current_screen_resolution == new_screen_resolution:
-        print "No need to change the screen resolution."
+        print("No need to change the screen resolution.")
     else:
-        print "Changing the screen resolution..."
+        print("Changing the screen resolution...")
         try:
             changeScreenResolution(new_screen_resolution["x"], new_screen_resolution["y"])
-        except Exception, e:
-            print "INFRA-ERROR: We have attempted to change the screen resolution but " + \
-                  "something went wrong: %s" % str(e)
+        except Exception as e:
+            print("INFRA-ERROR: We have attempted to change the screen resolution but " + \
+                  "something went wrong: %s" % str(e))
             return 1
         time.sleep(3)  # just in case
         current_screen_resolution = queryScreenResolution()
-        print "Screen resolution (new): (%(x)s, %(y)s)" % current_screen_resolution
+        print("Screen resolution (new): (%(x)s, %(y)s)" % current_screen_resolution)
 
-    print "Mouse position (current): (%(x)s, %(y)s)" % (queryMousePosition())
+    print("Mouse position (current): (%(x)s, %(y)s)" % (queryMousePosition()))
     setCursorPos(new_mouse_position["x"], new_mouse_position["y"])
     current_mouse_position = queryMousePosition()
-    print "Mouse position (new): (%(x)s, %(y)s)" % (current_mouse_position)
+    print("Mouse position (new): (%(x)s, %(y)s)" % (current_mouse_position))
 
     if current_screen_resolution != new_screen_resolution or current_mouse_position != new_mouse_position:
-        print "INFRA-ERROR: The new screen resolution or mouse positions are not what we expected"
+        print("INFRA-ERROR: The new screen resolution or mouse positions are not what we expected")
         return 1
     else:
         return 0
diff --git a/testing/mozharness/external_tools/robustcheckout.py b/testing/mozharness/external_tools/robustcheckout.py
index e801724c18..dc19ebcdb0 100644
--- a/testing/mozharness/external_tools/robustcheckout.py
+++ b/testing/mozharness/external_tools/robustcheckout.py
@@ -9,7 +9,6 @@ from a source repo using best practices to ensure optimal clone
 times and storage efficiency.
 """
 
-from __future__ import absolute_import
 
 import contextlib
 import errno
@@ -20,7 +19,7 @@ import re
 import socket
 import ssl
 import time
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
 from mercurial.i18n import _
 from mercurial.node import hex
@@ -314,7 +313,7 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase,
             ui.warn('ssl error: %s\n' % e)
             handlenetworkfailure()
             return True
-        elif isinstance(e, urllib2.URLError):
+        elif isinstance(e, six.moves.urllib.error.URLError):
             if isinstance(e.reason, socket.error):
                 ui.warn('socket error: %s\n' % e.reason)
                 handlenetworkfailure()
@@ -342,7 +341,7 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase,
         try:
             res = hg.clone(ui, {}, cloneurl, dest=dest, update=False,
                            shareopts={'pool': sharebase, 'mode': 'identity'})
-        except (error.Abort, ssl.SSLError, urllib2.URLError) as e:
+        except (error.Abort, ssl.SSLError, six.moves.urllib.error.URLError) as e:
             if handlepullerror(e):
                 return callself()
             raise
@@ -401,7 +400,7 @@ def _docheckout(ui, url, dest, upstream, revision, branch, purge, sharebase,
                 pullop = exchange.pull(repo, remote, heads=pullrevs)
                 if not pullop.rheads:
                     raise error.Abort('unable to pull requested revision')
-        except (error.Abort, ssl.SSLError, urllib2.URLError) as e:
+        except (error.Abort, ssl.SSLError, six.moves.urllib.error.URLError) as e:
             if handlepullerror(e):
                 return callself()
             raise
diff --git a/testing/mozharness/external_tools/virtualenv/setup.py b/testing/mozharness/external_tools/virtualenv/setup.py
index ee03bc5313..9d738d6b62 100644
--- a/testing/mozharness/external_tools/virtualenv/setup.py
+++ b/testing/mozharness/external_tools/virtualenv/setup.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import os
 import re
 import shutil
diff --git a/testing/mozharness/external_tools/virtualenv/site.py b/testing/mozharness/external_tools/virtualenv/site.py
index 4e426cdb66..5f7c992285 100644
--- a/testing/mozharness/external_tools/virtualenv/site.py
+++ b/testing/mozharness/external_tools/virtualenv/site.py
@@ -63,11 +63,12 @@ ImportError exception, it is silently ignored.
 
 """
 
+from __future__ import print_function
 import sys
 import os
 
 try:
-    import __builtin__ as builtins
+    import builtins as builtins
 except ImportError:
     import builtins
 try:
@@ -454,7 +455,7 @@ class _Printer(object):
         while 1:
             try:
                 for i in range(lineno, lineno + self.MAXLINES):
-                    print(self.__lines[i])
+                    print((self.__lines[i]))
             except IndexError:
                 break
             else:
@@ -462,9 +463,9 @@ class _Printer(object):
                 key = None
                 while key is None:
                     try:
-                        key = raw_input(prompt)
-                    except NameError:
                         key = input(prompt)
+                    except NameError:
+                        key = eval(input(prompt))
                     if key not in ('', 'q'):
                         key = None
                 if key == 'q':
@@ -723,16 +724,16 @@ def _script():
     if not args:
         print("sys.path = [")
         for dir in sys.path:
-            print("    %r," % (dir,))
+            print(("    %r," % (dir,)))
         print("]")
         def exists(path):
             if os.path.isdir(path):
                 return "exists"
             else:
                 return "doesn't exist"
-        print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
-        print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
-        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        print(("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE))))
+        print(("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE))))
+        print(("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE))
         sys.exit(0)
 
     buffer = []
@@ -742,7 +743,7 @@ def _script():
         buffer.append(USER_SITE)
 
     if buffer:
-        print(os.pathsep.join(buffer))
+        print((os.pathsep.join(buffer)))
         if ENABLE_USER_SITE:
             sys.exit(0)
         elif ENABLE_USER_SITE is False:
@@ -753,7 +754,7 @@ def _script():
             sys.exit(3)
     else:
         import textwrap
-        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        print((textwrap.dedent(help % (sys.argv[0], os.pathsep))))
         sys.exit(10)
 
 if __name__ == '__main__':
diff --git a/testing/mozharness/external_tools/virtualenv/virtualenv.py b/testing/mozharness/external_tools/virtualenv/virtualenv.py
index e363021cc1..a46fccaf69 100755
--- a/testing/mozharness/external_tools/virtualenv/virtualenv.py
+++ b/testing/mozharness/external_tools/virtualenv/virtualenv.py
@@ -1,8 +1,10 @@
 #!/usr/bin/env python
 """Create a "virtual" Python installation"""
 
+from __future__ import print_function
 import os
 import sys
+import six
 
 # If we are running in a new interpreter to create a virtualenv,
 # we do NOT want paths from our existing location interfering with anything,
@@ -32,7 +34,7 @@ from distutils.util import strtobool
 from os.path import join
 
 try:
-    import ConfigParser
+    import six.moves.configparser
 except ImportError:
     import configparser as ConfigParser
 
@@ -40,14 +42,14 @@ __version__ = "15.0.1"
 virtualenv_version = __version__  # legacy
 
 if sys.version_info < (2, 6):
-    print('ERROR: %s' % sys.exc_info()[1])
+    print(('ERROR: %s' % sys.exc_info()[1]))
     print('ERROR: this script requires Python 2.6 or greater.')
     sys.exit(101)
 
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1])
 
@@ -82,7 +84,7 @@ else:
     try:
         import winreg
     except ImportError:
-        import _winreg as winreg
+        import six.moves.winreg as winreg
 
     def get_installed_pythons():
         try:
@@ -427,7 +429,7 @@ class ConfigOptionParser(optparse.OptionParser):
     configuration files and environmental variables
     """
     def __init__(self, *args, **kwargs):
-        self.config = ConfigParser.RawConfigParser()
+        self.config = six.moves.configparser.RawConfigParser()
         self.files = self.get_config_files()
         self.config.read(self.files)
         optparse.OptionParser.__init__(self, *args, **kwargs)
@@ -473,7 +475,7 @@ class ConfigOptionParser(optparse.OptionParser):
                     val = option.convert_value(key, val)
                 except optparse.OptionValueError:
                     e = sys.exc_info()[1]
-                    print("An error occurred during configuration: %s" % e)
+                    print(("An error occurred during configuration: %s" % e))
                     sys.exit(3)
                 defaults[option.dest] = val
         return defaults
@@ -506,7 +508,7 @@ class ConfigOptionParser(optparse.OptionParser):
         defaults = self.update_defaults(self.defaults.copy())  # ours
         for option in self._get_all_options():
             default = defaults.get(option.dest)
-            if isinstance(default, basestring):
+            if isinstance(default, str):
                 opt_str = option.get_opt_string()
                 defaults[option.dest] = option.check_value(opt_str, default)
         return optparse.Values(defaults)
@@ -673,8 +675,8 @@ def main():
         parser.print_help()
         sys.exit(2)
     if len(args) > 1:
-        print('There must be only one argument: DEST_DIR (you gave %s)' % (
-            ' '.join(args)))
+        print(('There must be only one argument: DEST_DIR (you gave %s)' % (
+            ' '.join(args))))
         parser.print_help()
         sys.exit(2)
 
@@ -840,8 +842,8 @@ def install_wheel(project_names, py_executable, search_dirs=None,
     # PIP_FIND_LINKS uses space as the path separator and thus cannot have paths
     # with spaces in them. Convert any of those to local file:// URL form.
     try:
-        from urlparse import urljoin
-        from urllib import pathname2url
+        from urllib.parse import urljoin
+        from urllib.request import pathname2url
     except ImportError:
         from urllib.parse import urljoin
         from urllib.request import pathname2url
@@ -968,12 +970,12 @@ def path_locations(home_dir):
             size = max(len(home_dir)+1, 256)
             buf = ctypes.create_unicode_buffer(size)
             try:
-                u = unicode
+                u = str
             except NameError:
                 u = str
             ret = GetShortPathName(u(home_dir), buf, size)
             if not ret:
-                print('Error: the path "%s" has a space in it' % home_dir)
+                print(('Error: the path "%s" has a space in it' % home_dir))
                 print('We could not determine the short pathname for it.')
                 print('Exiting.')
                 sys.exit(3)
@@ -1520,7 +1522,7 @@ def fix_lib64(lib_dir, symlink=True):
         return
     # Check we have a lib64 library path
     if not [p for p in distutils.sysconfig.get_config_vars().values()
-            if isinstance(p, basestring) and 'lib64' in p]:
+            if isinstance(p, str) and 'lib64' in p]:
         return
 
     logger.debug('This system uses lib64; symlinking lib64 to lib')
diff --git a/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/distutils-init.py b/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/distutils-init.py
index 29fc1da459..fe392b712b 100644
--- a/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/distutils-init.py
+++ b/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/distutils-init.py
@@ -25,9 +25,9 @@ else:
 from distutils import dist, sysconfig
 
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 ## patch build_ext (distutils doesn't know how to get the libs directory
 ## path on windows - it hardcodes the paths around the patched sys.prefix)
@@ -38,7 +38,7 @@ if sys.platform == 'win32':
         def finalize_options (self):
             if self.library_dirs is None:
                 self.library_dirs = []
-            elif isinstance(self.library_dirs, basestring):
+            elif isinstance(self.library_dirs, str):
                 self.library_dirs = self.library_dirs.split(os.pathsep)
             
             self.library_dirs.insert(0, os.path.join(sys.real_prefix, "Libs"))
diff --git a/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/site.py b/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/site.py
index 7969769c36..2b14669adb 100644
--- a/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/site.py
+++ b/testing/mozharness/external_tools/virtualenv/virtualenv_embedded/site.py
@@ -63,10 +63,11 @@ ImportError exception, it is silently ignored.
 
 """
 
+from __future__ import print_function
 import sys
 import os
 try:
-    import __builtin__ as builtins
+    import builtins as builtins
 except ImportError:
     import builtins
 try:
@@ -453,7 +454,7 @@ class _Printer(object):
         while 1:
             try:
                 for i in range(lineno, lineno + self.MAXLINES):
-                    print(self.__lines[i])
+                    print((self.__lines[i]))
             except IndexError:
                 break
             else:
@@ -461,9 +462,9 @@ class _Printer(object):
                 key = None
                 while key is None:
                     try:
-                        key = raw_input(prompt)
-                    except NameError:
                         key = input(prompt)
+                    except NameError:
+                        key = eval(input(prompt))
                     if key not in ('', 'q'):
                         key = None
                 if key == 'q':
@@ -721,16 +722,16 @@ def _script():
     if not args:
         print("sys.path = [")
         for dir in sys.path:
-            print("    %r," % (dir,))
+            print(("    %r," % (dir,)))
         print("]")
         def exists(path):
             if os.path.isdir(path):
                 return "exists"
             else:
                 return "doesn't exist"
-        print("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE)))
-        print("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE)))
-        print("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE)
+        print(("USER_BASE: %r (%s)" % (USER_BASE, exists(USER_BASE))))
+        print(("USER_SITE: %r (%s)" % (USER_SITE, exists(USER_BASE))))
+        print(("ENABLE_USER_SITE: %r" %  ENABLE_USER_SITE))
         sys.exit(0)
 
     buffer = []
@@ -740,7 +741,7 @@ def _script():
         buffer.append(USER_SITE)
 
     if buffer:
-        print(os.pathsep.join(buffer))
+        print((os.pathsep.join(buffer)))
         if ENABLE_USER_SITE:
             sys.exit(0)
         elif ENABLE_USER_SITE is False:
@@ -751,7 +752,7 @@ def _script():
             sys.exit(3)
     else:
         import textwrap
-        print(textwrap.dedent(help % (sys.argv[0], os.pathsep)))
+        print((textwrap.dedent(help % (sys.argv[0], os.pathsep))))
         sys.exit(10)
 
 if __name__ == '__main__':
diff --git a/testing/mozharness/mach_commands.py b/testing/mozharness/mach_commands.py
index f453397db7..87e9304bd7 100644
--- a/testing/mozharness/mach_commands.py
+++ b/testing/mozharness/mach_commands.py
@@ -9,8 +9,9 @@ import os
 import re
 import subprocess
 import sys
-import urllib
-import urlparse
+import urllib.request
+import urllib.parse
+import urllib.error
 
 import mozinfo
 
@@ -137,7 +138,7 @@ class MozharnessRunner(MozbuildObject):
 
 
     def path_to_url(self, path):
-        return urlparse.urljoin('file:', urllib.pathname2url(path))
+        return urllib.parse.urljoin('file:', urllib.request.pathname2url(path))
 
     def _installer_url(self):
         package_re = {
diff --git a/testing/mozharness/mozfile/__init__.py b/testing/mozharness/mozfile/__init__.py
index 37b8babb80..b276d461df 100644
--- a/testing/mozharness/mozfile/__init__.py
+++ b/testing/mozharness/mozfile/__init__.py
@@ -2,4 +2,4 @@
 # 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 mozfile import *
+from .mozfile import *
diff --git a/testing/mozharness/mozfile/mozfile.py b/testing/mozharness/mozfile/mozfile.py
index ac0edcab4f..132262a72f 100644
--- a/testing/mozharness/mozfile/mozfile.py
+++ b/testing/mozharness/mozfile/mozfile.py
@@ -4,14 +4,15 @@
 # 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 print_function
 from contextlib import contextmanager
 import os
 import shutil
 import stat
 import tarfile
 import tempfile
-import urlparse
-import urllib2
+import six.moves.urllib.parse
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import zipfile
 import time
 
@@ -54,8 +55,8 @@ def extract_zip(src, dest):
     else:
         try:
             bundle = zipfile.ZipFile(src)
-        except Exception, e:
-            print "src: %s" % src
+        except Exception as e:
+            print("src: %s" % src)
             raise
 
     namelist = bundle.namelist()
@@ -161,7 +162,7 @@ def remove(path):
                     raise
                 retry_count += 1
 
-                print 'Retrying to remove "%s" because it is in use.' % path
+                print('Retrying to remove "%s" because it is in use.' % path)
                 time.sleep(retry_delay)
 
     if not os.path.exists(path):
@@ -347,7 +348,7 @@ def is_url(thing):
     Return True if thing looks like a URL.
     """
 
-    parsed = urlparse.urlparse(thing)
+    parsed = six.moves.urllib.parse.urlparse(thing)
     if 'scheme' in parsed:
         return len(parsed.scheme) >= 2
     else:
@@ -366,7 +367,7 @@ def load(resource):
 
     if not is_url(resource):
         # if no scheme is given, it is a file path
-        return file(resource)
+        return open(resource)
 
-    return urllib2.urlopen(resource)
+    return six.moves.urllib.request.urlopen(resource)
 
diff --git a/testing/mozharness/mozharness/base/config.py b/testing/mozharness/mozharness/base/config.py
index 9c17b33818..3af26cdba2 100644
--- a/testing/mozharness/mozharness/base/config.py
+++ b/testing/mozharness/mozharness/base/config.py
@@ -24,11 +24,12 @@ TODO:
   these settings are set.
 """
 
+from __future__ import print_function
 from copy import deepcopy
 from optparse import OptionParser, Option, OptionGroup
 import os
 import sys
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import socket
 import time
 try:
@@ -156,7 +157,7 @@ def parse_config_file(file_name, quiet=False, search_path=None,
     if file_name.endswith('.py'):
         global_dict = {}
         local_dict = {}
-        execfile(file_path, global_dict, local_dict)
+        exec(compile(open(file_path, "rb").read(), file_path, 'exec'), global_dict, local_dict)
         config = local_dict[config_dict_name]
     elif file_name.endswith('.json'):
         fh = open(file_path)
@@ -177,18 +178,18 @@ def download_config_file(url, file_name):
     max_sleeptime = 5 * 60
     while True:
         if n >= attempts:
-            print "Failed to download from url %s after %d attempts, quiting..." % (url, attempts)
+            print("Failed to download from url %s after %d attempts, quiting..." % (url, attempts))
             raise SystemError(-1)
         try:
-            contents = urllib2.urlopen(url, timeout=30).read()
+            contents = six.moves.urllib.request.urlopen(url, timeout=30).read()
             break
-        except urllib2.URLError, e:
-            print "Error downloading from url %s: %s" % (url, str(e))
-        except socket.timeout, e:
-            print "Time out accessing %s: %s" % (url, str(e))
-        except socket.error, e:
-            print "Socket error when accessing %s: %s" % (url, str(e))
-        print "Sleeping %d seconds before retrying" % sleeptime
+        except six.moves.urllib.error.URLError as e:
+            print("Error downloading from url %s: %s" % (url, str(e)))
+        except socket.timeout as e:
+            print("Time out accessing %s: %s" % (url, str(e)))
+        except socket.error as e:
+            print("Socket error when accessing %s: %s" % (url, str(e)))
+        print("Sleeping %d seconds before retrying" % sleeptime)
         time.sleep(sleeptime)
         sleeptime = sleeptime * 2
         if sleeptime > max_sleeptime:
@@ -199,8 +200,8 @@ def download_config_file(url, file_name):
         f = open(file_name, 'w')
         f.write(contents)
         f.close()
-    except IOError, e:
-        print "Error writing downloaded contents to file %s: %s" % (file_name, str(e))
+    except IOError as e:
+        print("Error writing downloaded contents to file %s: %s" % (file_name, str(e)))
         raise SystemError(-1)
 
 
@@ -390,8 +391,8 @@ class BaseConfig(object):
         for action in action_list:
             if action not in self.all_actions:
                 if not quiet:
-                    print("Invalid action %s not in %s!" % (action,
-                                                            self.all_actions))
+                    print(("Invalid action %s not in %s!" % (action,
+                                                            self.all_actions)))
                 raise SystemExit(-1)
         return action_list
 
@@ -401,17 +402,17 @@ class BaseConfig(object):
             sorted_indexes = sorted(indexes)
             for i in range(len(indexes)):
                 if indexes[i] != sorted_indexes[i]:
-                    print(("Action %s comes in different order in %s\n" +
-                           "than in %s") % (action_list[i], action_list, self.all_actions))
+                    print((("Action %s comes in different order in %s\n" +
+                           "than in %s") % (action_list[i], action_list, self.all_actions)))
                     raise SystemExit(-1)
         except ValueError as e:
-            print("Invalid action found: " + str(e))
+            print(("Invalid action found: " + str(e)))
             raise SystemExit(-1)
 
     def list_actions(self):
-        print "Actions available:"
+        print("Actions available:")
         for a in self.all_actions:
-            print "    " + ("*" if a in self.default_actions else " "), a
+            print("    " + ("*" if a in self.default_actions else " "), a)
         raise SystemExit(0)
 
     def get_cfgs_from_files(self, all_config_files, options):
@@ -446,9 +447,9 @@ class BaseConfig(object):
                     all_cfg_files_and_dicts.append((cf, parse_config_file(cf)))
             except Exception:
                 if cf in options.opt_config_files:
-                    print(
+                    print((
                         "WARNING: optional config file not found %s" % cf
-                    )
+                    ))
                 else:
                     raise
         return all_cfg_files_and_dicts
diff --git a/testing/mozharness/mozharness/base/diskutils.py b/testing/mozharness/mozharness/base/diskutils.py
index 745384ff92..726f90ecc6 100644
--- a/testing/mozharness/mozharness/base/diskutils.py
+++ b/testing/mozharness/mozharness/base/diskutils.py
@@ -116,7 +116,7 @@ class DiskSize(object):
         # depending on path format (unicode or not) and python version (2 or 3)
         # we need to call GetDiskFreeSpaceExW or GetDiskFreeSpaceExA
         called_function = ctypes.windll.kernel32.GetDiskFreeSpaceExA
-        if isinstance(path, unicode) or sys.version_info >= (3,):
+        if isinstance(path, str) or sys.version_info >= (3,):
             called_function = ctypes.windll.kernel32.GetDiskFreeSpaceExW
         # we're ready for the dll call. On error it returns 0
         if called_function(path,
diff --git a/testing/mozharness/mozharness/base/log.py b/testing/mozharness/mozharness/base/log.py
index 2c18b50c33..edaa27e5c1 100755
--- a/testing/mozharness/mozharness/base/log.py
+++ b/testing/mozharness/mozharness/base/log.py
@@ -24,6 +24,7 @@ TODO:
 - log rotation config
 """
 
+from __future__ import print_function
 from datetime import datetime
 import logging
 import os
@@ -91,9 +92,9 @@ class LogMixin(object):
         """
         if not hasattr(self, 'config') or self.config.get('log_to_console', True):
             if stderr:
-                print >> sys.stderr, message
+                print(message, file=sys.stderr)
             else:
-                print message
+                print(message)
 
     def log(self, message, level=INFO, exit_code=-1):
         """ log the message passed to it according to level, exit if level == FATAL
@@ -340,7 +341,7 @@ class OutputParser(LogMixin):
             output (str | list): string or list of string to parse
         """
 
-        if isinstance(output, basestring):
+        if isinstance(output, str):
             output = [output]
         for line in output:
             if not line or line.isspace():
diff --git a/testing/mozharness/mozharness/base/python.py b/testing/mozharness/mozharness/base/python.py
index cb5bfbc46c..b13df1fa74 100644
--- a/testing/mozharness/mozharness/base/python.py
+++ b/testing/mozharness/mozharness/base/python.py
@@ -14,7 +14,7 @@ import sys
 import json
 import socket
 import traceback
-import urlparse
+import six.moves.urllib.parse
 
 import mozharness
 from mozharness.base.script import (
@@ -26,6 +26,7 @@ from mozharness.base.script import (
 from mozharness.base.errors import VirtualenvErrorList
 from mozharness.base.log import WARNING, FATAL
 from mozharness.mozilla.proxxy import Proxxy
+import six
 
 external_tools_path = os.path.join(
     os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))),
@@ -162,7 +163,7 @@ class VirtualenvMixin(object):
                 self.log("package_versions: Program pip not in path", level=error_level)
                 return {}
             pip_freeze_output = self.get_output_from_command([pip, "freeze"], silent=True, ignore_errors=True)
-            if not isinstance(pip_freeze_output, basestring):
+            if not isinstance(pip_freeze_output, str):
                 self.fatal("package_versions: Error encountered running `pip freeze`: %s" % pip_freeze_output)
 
         for line in pip_freeze_output.splitlines():
@@ -190,7 +191,7 @@ class VirtualenvMixin(object):
         """
         Return whether the package is installed
         """
-        packages = self.package_versions(error_level=error_level).keys()
+        packages = list(self.package_versions(error_level=error_level).keys())
         return package_name.lower() in [package.lower() for package in packages]
 
     def install_module(self, module=None, module_url=None, install_method=None,
@@ -255,7 +256,7 @@ class VirtualenvMixin(object):
         proxxy = Proxxy(self.config, self.log_obj)
         trusted_hosts = set()
         for link in proxxy.get_proxies_and_urls(c.get('find_links', [])):
-            parsed = urlparse.urlparse(link)
+            parsed = six.moves.urllib.parse.urlparse(link)
 
             try:
                 socket.gethostbyname(parsed.hostname)
@@ -434,7 +435,7 @@ class VirtualenvMixin(object):
         """Import the virtualenv's packages into this Python interpreter."""
         bin_dir = os.path.dirname(self.query_python_path())
         activate = os.path.join(bin_dir, 'activate_this.py')
-        execfile(activate, dict(__file__=activate))
+        exec(compile(open(activate, "rb").read(), activate, 'exec'), dict(__file__=activate))
 
 
 # This is (sadly) a mixin for logging methods.
diff --git a/testing/mozharness/mozharness/base/script.py b/testing/mozharness/mozharness/base/script.py
index 828f4e39e8..e3b56524ac 100755
--- a/testing/mozharness/mozharness/base/script.py
+++ b/testing/mozharness/mozharness/base/script.py
@@ -11,6 +11,7 @@ script.py, along with config.py and log.py, represents the core of
 mozharness.
 """
 
+from __future__ import print_function
 import codecs
 from contextlib import contextmanager
 import datetime
@@ -31,11 +32,12 @@ import sys
 import tarfile
 import time
 import traceback
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import zipfile
-import httplib
-import urlparse
+import six.moves.http_client
+import six.moves.urllib.parse
 import hashlib
+import six
 if os.name == 'nt':
     try:
         import win32file
@@ -246,7 +248,7 @@ class ScriptMixin(PlatformMixin):
             str: in case `path` is a string. The result is the path with the new notation.
             type(path): `path` itself is returned in case `path` is not str type.
         """
-        if not isinstance(path, basestring):
+        if not isinstance(path, str):
             return path
         path = path.replace("\\", "/")
 
@@ -316,7 +318,7 @@ class ScriptMixin(PlatformMixin):
                  of the url.
         """
 
-        parsed = urlparse.urlsplit(url.rstrip('/'))
+        parsed = six.moves.urllib.parse.urlsplit(url.rstrip('/'))
         if parsed.path != '':
             return parsed.path.rsplit('/', 1)[-1]
         else:
@@ -342,8 +344,8 @@ class ScriptMixin(PlatformMixin):
         https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
         """
         # http://bugs.python.org/issue13359 - urllib2 does not automatically quote the URL
-        url_quoted = urllib2.quote(url, safe='%/:=&?~#+!$,;\'@()*[]|')
-        return urllib2.urlopen(url_quoted, **kwargs)
+        url_quoted = six.moves.urllib.parse.quote(url, safe='%/:=&?~#+!$,;\'@()*[]|')
+        return six.moves.urllib.request.urlopen(url_quoted, **kwargs)
 
 
 
@@ -363,7 +365,7 @@ class ScriptMixin(PlatformMixin):
             BytesIO: contents of url
         '''
         self.info('Fetch {} into memory'.format(url))
-        parsed_url = urlparse.urlparse(url)
+        parsed_url = six.moves.urllib.parse.urlparse(url)
 
         if parsed_url.scheme in ('', 'file'):
             if not os.path.isfile(url):
@@ -374,9 +376,9 @@ class ScriptMixin(PlatformMixin):
             # In case we're referrencing a file without file://
             if parsed_url.scheme == '':
                 url = 'file://%s' % os.path.abspath(url)
-                parsed_url = urlparse.urlparse(url)
+                parsed_url = six.moves.urllib.parse.urlparse(url)
 
-        request = urllib2.Request(url)
+        request = six.moves.urllib.request.Request(url)
         # When calling fetch_url_into_memory() you should retry when we raise one of these exceptions:
         # * Bug 1300663 - HTTPError: HTTP Error 404: Not Found
         # * Bug 1300413 - HTTPError: HTTP Error 500: Internal Server Error
@@ -389,7 +391,7 @@ class ScriptMixin(PlatformMixin):
         # * Bug 1301807 - BadStatusLine: ''
         #
         # Bug 1309912 - Adding timeout in hopes to solve blocking on response.read() (bug 1300413)
-        response = urllib2.urlopen(request, timeout=30)
+        response = six.moves.urllib.request.urlopen(request, timeout=30)
 
         if parsed_url.scheme in ('http', 'https'):
             expected_file_size = int(response.headers.get('Content-Length'))
@@ -453,17 +455,17 @@ class ScriptMixin(PlatformMixin):
                 block = f.read(1024 ** 2)
                 if not block:
                     if f_length is not None and got_length != f_length:
-                        raise urllib2.URLError("Download incomplete; content-length was %d, but only received %d" % (f_length, got_length))
+                        raise six.moves.urllib.error.URLError("Download incomplete; content-length was %d, but only received %d" % (f_length, got_length))
                     break
                 local_file.write(block)
                 if f_length is not None:
                     got_length += len(block)
             local_file.close()
             return file_name
-        except urllib2.HTTPError, e:
+        except six.moves.urllib.error.HTTPError as e:
             self.warning("Server returned status %s %s for %s" % (str(e.code), str(e), url))
             raise
-        except urllib2.URLError, e:
+        except six.moves.urllib.error.URLError as e:
             self.warning("URL Error: %s" % url)
 
             # Failures due to missing local files won't benefit from retry.
@@ -471,7 +473,7 @@ class ScriptMixin(PlatformMixin):
             if isinstance(e.args[0], OSError) and e.args[0].errno == errno.ENOENT:
                 raise e.args[0]
 
-            remote_host = urlparse.urlsplit(url)[1]
+            remote_host = six.moves.urllib.parse.urlsplit(url)[1]
             if remote_host:
                 nslookup = self.query_exe('nslookup')
                 error_list = [{
@@ -482,10 +484,10 @@ class ScriptMixin(PlatformMixin):
                 self.run_command([nslookup, remote_host],
                                  error_list=error_list)
             raise
-        except socket.timeout, e:
+        except socket.timeout as e:
             self.warning("Timed out accessing %s: %s" % (url, str(e)))
             raise
-        except socket.error, e:
+        except socket.error as e:
             self.warning("Socket error when accessing %s: %s" % (url, str(e)))
             raise
 
@@ -511,8 +513,8 @@ class ScriptMixin(PlatformMixin):
         """
         retry_args = dict(
             failure_status=None,
-            retry_exceptions=(urllib2.HTTPError, urllib2.URLError,
-                              httplib.BadStatusLine,
+            retry_exceptions=(six.moves.urllib.error.HTTPError, six.moves.urllib.error.URLError,
+                              six.moves.http_client.BadStatusLine,
                               socket.timeout, socket.error),
             error_message="Can't download from %s to %s!" % (url, file_name),
             error_level=error_level,
@@ -537,7 +539,7 @@ class ScriptMixin(PlatformMixin):
     def _filter_entries(self, namelist, extract_dirs):
         """Filter entries of the archive based on the specified list of to extract dirs."""
         filter_partial = functools.partial(fnmatch.filter, namelist)
-        entries = itertools.chain(*map(filter_partial, extract_dirs or ['*']))
+        entries = itertools.chain(*list(map(filter_partial, extract_dirs or ['*'])))
 
         for entry in entries:
             yield entry
@@ -666,9 +668,9 @@ class ScriptMixin(PlatformMixin):
         # 1) Let's fetch the file
         retry_args = dict(
             retry_exceptions=(
-                urllib2.HTTPError,
-                urllib2.URLError,
-                httplib.BadStatusLine,
+                six.moves.urllib.error.HTTPError,
+                six.moves.urllib.error.URLError,
+                six.moves.http_client.BadStatusLine,
                 socket.timeout,
                 socket.error,
                 FetchedIncorrectFilesize,
@@ -768,11 +770,11 @@ class ScriptMixin(PlatformMixin):
         try:
             shutil.move(src, dest)
         # http://docs.python.org/tutorial/errors.html
-        except IOError, e:
+        except IOError as e:
             self.log("IO error: %s" % str(e),
                      level=error_level, exit_code=exit_code)
             return -1
-        except shutil.Error, e:
+        except shutil.Error as e:
             self.log("shutil error: %s" % str(e),
                      level=error_level, exit_code=exit_code)
             return -1
@@ -819,7 +821,7 @@ class ScriptMixin(PlatformMixin):
                 outfile.writelines(infile)
                 outfile.close()
                 infile.close()
-            except IOError, e:
+            except IOError as e:
                 self.log("Can't compress %s to %s: %s!" % (src, dest, str(e)),
                          level=error_level)
                 return -1
@@ -827,7 +829,7 @@ class ScriptMixin(PlatformMixin):
             self.log("Copying %s to %s" % (src, dest), level=log_level)
             try:
                 shutil.copyfile(src, dest)
-            except (IOError, shutil.Error), e:
+            except (IOError, shutil.Error) as e:
                 self.log("Can't copy %s to %s: %s!" % (src, dest, str(e)),
                          level=error_level)
                 return -1
@@ -835,7 +837,7 @@ class ScriptMixin(PlatformMixin):
         if copystat:
             try:
                 shutil.copystat(src, dest)
-            except (IOError, shutil.Error), e:
+            except (IOError, shutil.Error) as e:
                 self.log("Can't copy attributes of %s to %s: %s!" % (src, dest, str(e)),
                          level=error_level)
                 return -1
@@ -968,7 +970,7 @@ class ScriptMixin(PlatformMixin):
         self.info("Reading from file %s" % file_path)
         try:
             fh = open(file_path, open_mode)
-        except IOError, err:
+        except IOError as err:
             self.log("unable to open %s: %s" % (file_path, err.strerror),
                      level=error_level)
             yield None, err
@@ -1111,7 +1113,7 @@ class ScriptMixin(PlatformMixin):
                 status = action(*args, **kwargs)
                 if good_statuses and status not in good_statuses:
                     retry = True
-            except retry_exceptions, e:
+            except retry_exceptions as e:
                 retry = True
                 error_message = "%s\nCaught exception: %s" % (error_message, str(e))
                 self.log('retry: attempt #%d caught exception: %s' % (n, str(e)), level=INFO)
@@ -1232,7 +1234,7 @@ class ScriptMixin(PlatformMixin):
         if isinstance(exe, dict):
             found = False
             # allow for searchable paths of the buildbot exe
-            for name, path in exe.iteritems():
+            for name, path in exe.items():
                 if isinstance(path, list) or isinstance(path, tuple):
                     path = [x % repl_dict for x in path]
                     if all([os.path.exists(section) for section in path]):
@@ -1390,7 +1392,7 @@ class ScriptMixin(PlatformMixin):
                             break
                         parser.add_lines(line)
                 returncode = p.returncode
-        except OSError, e:
+        except OSError as e:
             level = error_level
             if halt_on_failure:
                 level = FATAL
@@ -2149,7 +2151,7 @@ class BaseScript(ScriptMixin, LogMixin, object):
                 except ValueError:
                     """log is closed; print as a default. Ran into this
                     when calling from __del__()"""
-                    print "### Log is closed! (%s)" % item['message']
+                    print("### Log is closed! (%s)" % item['message'])
 
     def add_summary(self, message, level=INFO):
         self.summary_list.append({'message': message, 'level': level})
diff --git a/testing/mozharness/mozharness/base/transfer.py b/testing/mozharness/mozharness/base/transfer.py
index 014c665a14..a298abfdab 100755
--- a/testing/mozharness/mozharness/base/transfer.py
+++ b/testing/mozharness/mozharness/base/transfer.py
@@ -9,7 +9,7 @@
 
 import os
 import pprint
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 try:
     import simplejson as json
     assert json
@@ -114,7 +114,7 @@ class TransferMixin(object):
         self.log("Attempting to download %s; timeout=%i" % (url, timeout),
                  level=log_level)
         try:
-            r = urllib2.urlopen(url, timeout=timeout)
+            r = six.moves.urllib.request.urlopen(url, timeout=timeout)
             j = json.load(r)
             self.log(pprint.pformat(j), level=log_level)
         except:
diff --git a/testing/mozharness/mozharness/base/vcs/gittool.py b/testing/mozharness/mozharness/base/vcs/gittool.py
index d6c609ea02..b835bacb94 100644
--- a/testing/mozharness/mozharness/base/vcs/gittool.py
+++ b/testing/mozharness/mozharness/base/vcs/gittool.py
@@ -1,6 +1,6 @@
 import os
 import re
-import urlparse
+import six.moves.urllib.parse
 
 from mozharness.base.script import ScriptMixin
 from mozharness.base.log import LogMixin, OutputParser
@@ -80,8 +80,8 @@ class GittoolVCS(ScriptMixin, LogMixin):
             cmd.append('--clean')
 
         for base_mirror_url in self.config.get('gittool_base_mirror_urls', self.config.get('vcs_base_mirror_urls', [])):
-            bits = urlparse.urlparse(repo)
-            mirror_url = urlparse.urljoin(base_mirror_url, bits.path)
+            bits = six.moves.urllib.parse.urlparse(repo)
+            mirror_url = six.moves.urllib.parse.urljoin(base_mirror_url, bits.path)
             cmd.extend(['--mirror', mirror_url])
 
         cmd.extend([repo, dest])
diff --git a/testing/mozharness/mozharness/base/vcs/mercurial.py b/testing/mozharness/mozharness/base/vcs/mercurial.py
index 71e5e3ea03..e89b1643b8 100755
--- a/testing/mozharness/mozharness/base/vcs/mercurial.py
+++ b/testing/mozharness/mozharness/base/vcs/mercurial.py
@@ -11,7 +11,7 @@ import os
 import re
 import subprocess
 from collections import namedtuple
-from urlparse import urlsplit
+from urllib.parse import urlsplit
 import hashlib
 
 import sys
@@ -299,7 +299,7 @@ class MercurialVCS(ScriptMixin, LogMixin, TransferMixin):
                         branch = "default"
                     revs.append((rev, branch))
                 return revs
-            except subprocess.CalledProcessError, inst:
+            except subprocess.CalledProcessError as inst:
                 # In some situations, some versions of Mercurial return "1"
                 # if no changes are found, so we need to ignore this return
                 # code
@@ -419,7 +419,7 @@ class MercurialVCS(ScriptMixin, LogMixin, TransferMixin):
                           ssh_username=ssh_username,
                           ssh_key=ssh_key)
                 return
-            except VCSException, e:
+            except VCSException as e:
                 self.debug("Hit error when trying to push: %s" % str(e))
                 if n == max_attempts:
                     self.debug("Tried %d times, giving up" % max_attempts)
@@ -435,7 +435,7 @@ class MercurialVCS(ScriptMixin, LogMixin, TransferMixin):
                     self.run_command(self.hg + ['rebase'], cwd=localrepo,
                                      error_list=HgErrorList,
                                      throw_exception=True)
-                except subprocess.CalledProcessError, e:
+                except subprocess.CalledProcessError as e:
                     self.debug("Failed to rebase: %s" % str(e))
                     # clean up any hanging rebase. ignore errors if we aren't
                     # in the middle of a rebase.
@@ -481,7 +481,7 @@ class MercurialVCS(ScriptMixin, LogMixin, TransferMixin):
             #
             # So we grab the first element ("28537" in this case) and then pull
             # out the 'date' field.
-            pushid = contents.iterkeys().next()
+            pushid = next(contents.keys())
             self.info('Pushid is: %s' % pushid)
             pushdate = contents[pushid]['date']
             self.info('Pushdate is: %s' % pushdate)
diff --git a/testing/mozharness/mozharness/lib/python/authentication.py b/testing/mozharness/mozharness/lib/python/authentication.py
index 2e5f83f373..6944d2321b 100644
--- a/testing/mozharness/mozharness/lib/python/authentication.py
+++ b/testing/mozharness/mozharness/lib/python/authentication.py
@@ -5,6 +5,7 @@
 # ***** END LICENSE BLOCK *****
 
 """module for http authentication operations"""
+from __future__ import print_function
 import getpass
 import os
 
@@ -33,15 +34,15 @@ def get_credentials():
             os.remove(CREDENTIALS_PATH)
     else:
         https_username = \
-                raw_input("Please enter your full LDAP email address: ")
+                input("Please enter your full LDAP email address: ")
 
         with open(CREDENTIALS_PATH, "w+") as file_handler:
             file_handler.write("%s\n" % https_username)
 
-        os.chmod(CREDENTIALS_PATH, 0600)
+        os.chmod(CREDENTIALS_PATH, 0o600)
 
     if not LDAP_PASSWORD:
-        print "Please enter your LDAP password (we won't store it):"
+        print("Please enter your LDAP password (we won't store it):")
         LDAP_PASSWORD = getpass.getpass()
 
     return https_username, LDAP_PASSWORD
diff --git a/testing/mozharness/mozharness/mozilla/bouncer/submitter.py b/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
index 43983dca8d..7c92671eb1 100644
--- a/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
+++ b/testing/mozharness/mozharness/mozilla/bouncer/submitter.py
@@ -1,10 +1,10 @@
 import base64
-import httplib
+import six.moves.http_client
 import socket
 import sys
 import traceback
-import urllib
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 from xml.dom.minidom import parseString
 
 from mozharness.base.log import FATAL
@@ -16,7 +16,7 @@ class BouncerSubmitterMixin(object):
             return self.credentials
         global_dict = {}
         local_dict = {}
-        execfile(self.config["credentials_file"], global_dict, local_dict)
+        exec(compile(open(self.config["credentials_file"], "rb").read(), self.config["credentials_file"], 'exec'), global_dict, local_dict)
         self.credentials = (local_dict["tuxedoUsername"],
                             local_dict["tuxedoPassword"])
         return self.credentials
@@ -24,8 +24,8 @@ class BouncerSubmitterMixin(object):
     def api_call(self, route, data, error_level=FATAL, retry_config=None):
         retry_args = dict(
             failure_status=None,
-            retry_exceptions=(urllib2.HTTPError, urllib2.URLError,
-                              httplib.BadStatusLine,
+            retry_exceptions=(six.moves.urllib.error.HTTPError, six.moves.urllib.error.URLError,
+                              six.moves.http_client.BadStatusLine,
                               socket.timeout, socket.error),
             error_message="call to %s failed" % (route),
             error_level=error_level,
@@ -43,9 +43,9 @@ class BouncerSubmitterMixin(object):
     def _api_call(self, route, data):
         api_prefix = self.config["bouncer-api-prefix"]
         api_url = "%s/%s" % (api_prefix, route)
-        request = urllib2.Request(api_url)
+        request = six.moves.urllib.request.Request(api_url)
         if data:
-            post_data = urllib.urlencode(data, doseq=True)
+            post_data = six.moves.urllib.parse.urlencode(data, doseq=True)
             request.add_data(post_data)
             self.info("POST data: %s" % post_data)
         credentials = self.query_credentials()
@@ -54,17 +54,17 @@ class BouncerSubmitterMixin(object):
             request.add_header("Authorization", "Basic %s" % auth.strip())
         try:
             self.info("Submitting to %s" % api_url)
-            res = urllib2.urlopen(request, timeout=60).read()
+            res = six.moves.urllib.request.urlopen(request, timeout=60).read()
             self.info("Server response")
             self.info(res)
             return res
-        except urllib2.HTTPError as e:
+        except six.moves.urllib.error.HTTPError as e:
             self.warning("Cannot access %s" % api_url)
             traceback.print_exc(file=sys.stdout)
             self.warning("Returned page source:")
             self.warning(e.read())
             raise
-        except urllib2.URLError:
+        except six.moves.urllib.error.URLError:
             traceback.print_exc(file=sys.stdout)
             self.warning("Cannot access %s" % api_url)
             raise
@@ -74,14 +74,14 @@ class BouncerSubmitterMixin(object):
         except socket.error as e:
             self.warning("Socket error when accessing %s: %s" % (api_url, e))
             raise
-        except httplib.BadStatusLine as e:
+        except six.moves.http_client.BadStatusLine as e:
             self.warning('BadStatusLine accessing %s: %s' % (api_url, e))
             raise
 
     def product_exists(self, product_name):
         self.info("Checking if %s already exists" % product_name)
         res = self.api_call("product_show?product=%s" %
-                            urllib.quote(product_name), data=None)
+                            six.moves.urllib.parse.quote(product_name), data=None)
         try:
             xml = parseString(res)
             # API returns <products/> if the product doesn't exist
diff --git a/testing/mozharness/mozharness/mozilla/buildbot.py b/testing/mozharness/mozharness/mozilla/buildbot.py
index e17343633b..78e34bf558 100755
--- a/testing/mozharness/mozharness/mozilla/buildbot.py
+++ b/testing/mozharness/mozharness/mozilla/buildbot.py
@@ -133,7 +133,7 @@ class BuildbotMixin(object):
         if not os.path.isdir(dir_name):
             self.mkdir_p(dir_name)
         if not prop_list:
-            prop_list = self.buildbot_properties.keys()
+            prop_list = list(self.buildbot_properties.keys())
             self.info("Writing buildbot properties to %s" % file_name)
         else:
             if not isinstance(prop_list, (list, tuple)):
@@ -171,7 +171,7 @@ class BuildbotMixin(object):
             if self.buildbot_config['sourcestamp']['changes'][0].get('comments'):
                 sendchange += ['--comments', self.buildbot_config['sourcestamp']['changes'][0]['comments'].encode('ascii', 'ignore')]
         if sendchange_props:
-            for key, value in sendchange_props.iteritems():
+            for key, value in sendchange_props.items():
                 sendchange.extend(['--property', '%s:%s' % (key, value)])
         else:
             if self.buildbot_config["properties"].get("builduid"):
diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py
index 9fd507816d..b20e74298a 100755
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -55,7 +55,7 @@ from mozharness.base.python import (
     VirtualenvMixin,
 )
 
-AUTOMATION_EXIT_CODES = EXIT_STATUS_DICT.values()
+AUTOMATION_EXIT_CODES = list(EXIT_STATUS_DICT.values())
 AUTOMATION_EXIT_CODES.sort()
 
 MISSING_CFG_KEY_MSG = "The key '%s' could not be determined \
@@ -466,7 +466,7 @@ class BuildOptionParser(object):
                      "shortname: %s \n\t-- a valid path in %s \n\t-- a "
                      "valid variant for the given platform and bits." % (
                          prospective_cfg_path,
-                         str(cls.build_variants.keys()),
+                         str(list(cls.build_variants.keys())),
                          str(cls.config_file_search_path)))
         parser.values.config_files.append(valid_variant_cfg_path)
         setattr(parser.values, option.dest, value)  # the pool
@@ -528,7 +528,7 @@ BUILD_BASE_CONFIG_OPTIONS = [
         "help": "Sets the build type and will determine appropriate"
                 " additional config to use. Either pass a config path"
                 " or use a valid shortname from: "
-                "%s" % (BuildOptionParser.build_variants.keys(),)}],
+                "%s" % (list(BuildOptionParser.build_variants.keys()),)}],
     [['--build-pool'], {
         "action": "callback",
         "callback": BuildOptionParser.set_build_pool,
@@ -676,7 +676,7 @@ platform '%(platform)s'. Updating self.config with the following from \
                     }
                 )
         if c.get("platform_overrides"):
-            if c['stage_platform'] in c['platform_overrides'].keys():
+            if c['stage_platform'] in list(c['platform_overrides'].keys()):
                 self.info(
                     pf_override_msg % {
                         'branch': c['branch'],
@@ -960,7 +960,7 @@ or run without that action (ie: --no-{action})"
         dirs = self.query_abs_dirs()
         check_test_env = {}
         if c.get('check_test_env'):
-            for env_var, env_value in c['check_test_env'].iteritems():
+            for env_var, env_value in c['check_test_env'].items():
                 check_test_env[env_var] = env_value % dirs
         return check_test_env
 
@@ -1224,8 +1224,8 @@ or run without that action (ie: --no-{action})"
         # persisted to file rather than use whats in the buildbot_properties
         # live object so we become less action dependant.
         all_current_props = dict(
-            chain(self.buildbot_config['properties'].items(),
-                  self.buildbot_properties.items())
+            chain(list(self.buildbot_config['properties'].items()),
+                  list(self.buildbot_properties.items()))
         )
         # graph_server_post.py expects a file with 'properties' key
         graph_props = dict(properties=all_current_props)
@@ -1250,7 +1250,7 @@ or run without that action (ie: --no-{action})"
                 if console_output:
                     self.info("Properties set from 'mach build'")
                     self.info(pprint.pformat(build_props))
-            for key, prop in build_props.iteritems():
+            for key, prop in build_props.items():
                 if prop != 'UNKNOWN':
                     self.set_buildbot_property(key, prop, write_to_file=True)
         else:
@@ -1341,7 +1341,7 @@ or run without that action (ie: --no-{action})"
         dirs = self.query_abs_dirs()
         auth = os.path.join(os.getcwd(), self.config['taskcluster_credentials_file'])
         credentials = {}
-        execfile(auth, credentials)
+        exec(compile(open(auth, "rb").read(), auth, 'exec'), credentials)
         self.client_id = credentials.get('taskcluster_clientId')
         self.access_token = credentials.get('taskcluster_accessToken')
 
@@ -2147,7 +2147,7 @@ or run without that action (ie: --no-{action})"
                            "Valid return codes %s" % (self.return_code,
                                                       AUTOMATION_EXIT_CODES))
                 self.return_code = 2
-            for status, return_code in EXIT_STATUS_DICT.iteritems():
+            for status, return_code in EXIT_STATUS_DICT.items():
                 if return_code == self.return_code:
                     self.buildbot_status(status, TBPL_STATUS_DICT[status])
         self.summary()
diff --git a/testing/mozharness/mozharness/mozilla/building/hazards.py b/testing/mozharness/mozharness/mozilla/building/hazards.py
index 6de235f892..3653c165ba 100644
--- a/testing/mozharness/mozharness/mozilla/building/hazards.py
+++ b/testing/mozharness/mozharness/mozilla/building/hazards.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import os
 import json
 import re
@@ -104,7 +105,7 @@ jobs = 4
 """ % values
 
         defaults_path = os.path.join(analysis_dir, 'defaults.py')
-        file(defaults_path, "w").write(defaults)
+        open(defaults_path, "w").write(defaults)
         builder.log("Wrote analysis config file " + defaults_path)
 
         build_script = builder.config['build_command']
@@ -165,14 +166,14 @@ jobs = 4
                  ('hazards.txt',
                   'hazards',
                   'list of just the hazards, together with gcFunction reason for each'))
-        for f, short, long in files:
+        for f, short, int in files:
             builder.copy_to_upload_dir(os.path.join(analysis_dir, f),
                                        short_desc=short,
-                                       long_desc=long,
+                                       long_desc=int,
                                        compress=False,  # blobber will compress
                                        upload_dir=upload_dir)
         print("== Hazards (temporarily inline here, beware weirdly interleaved output, see bug 1211402) ==")
-        print(file(os.path.join(analysis_dir, "hazards.txt")).read())
+        print((open(os.path.join(analysis_dir, "hazards.txt")).read()))
 
     def upload_results(self, builder):
         """Upload the results of the analysis."""
diff --git a/testing/mozharness/mozharness/mozilla/l10n/locales.py b/testing/mozharness/mozharness/mozilla/l10n/locales.py
index 24920ae445..f6fad57aa3 100755
--- a/testing/mozharness/mozharness/mozilla/l10n/locales.py
+++ b/testing/mozharness/mozharness/mozilla/l10n/locales.py
@@ -8,7 +8,7 @@
 """
 
 import os
-from urlparse import urljoin
+from urllib.parse import urljoin
 import sys
 from copy import deepcopy
 
diff --git a/testing/mozharness/mozharness/mozilla/mapper.py b/testing/mozharness/mozharness/mozilla/mapper.py
index c5a2d48959..3cc3e00797 100644
--- a/testing/mozharness/mozharness/mozilla/mapper.py
+++ b/testing/mozharness/mozharness/mozilla/mapper.py
@@ -6,7 +6,7 @@
 # ***** END LICENSE BLOCK *****
 """Support for hg/git mapper
 """
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import time
 try:
     import simplejson as json
@@ -47,7 +47,7 @@ class MapperMixin:
         n = 1
         while n <= attempts:
             try:
-                r = urllib2.urlopen(url, timeout=10)
+                r = six.moves.urllib.request.urlopen(url, timeout=10)
                 j = json.loads(r.readline())
                 if j['%s_rev' % vcs] is None:
                     if require_answer:
@@ -55,7 +55,7 @@ class MapperMixin:
                     else:
                         self.warning("Mapper returned a revision of None.  Accepting because require_answer is False.")
                 return j['%s_rev' % vcs]
-            except Exception, err:
+            except Exception as err:
                 self.warning('Error: %s' % str(err))
                 if n == attempts:
                     self.fatal('Giving up on %s %s revision for %s.' % (project_name, vcs, rev))
diff --git a/testing/mozharness/mozharness/mozilla/mar.py b/testing/mozharness/mozharness/mozilla/mar.py
index dbe3b96a0d..f8cc860788 100644
--- a/testing/mozharness/mozharness/mozilla/mar.py
+++ b/testing/mozharness/mozharness/mozilla/mar.py
@@ -8,7 +8,7 @@
 
 import os
 import sys
-import ConfigParser
+import six.moves.configparser
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(sys.path[0]))
@@ -21,7 +21,7 @@ CONFIG = {
 
 
 def query_ini_file(ini_file, section, option):
-    ini = ConfigParser.SafeConfigParser()
+    ini = six.moves.configparser.SafeConfigParser()
     ini.read(ini_file)
     return ini.get(section, option)
 
@@ -67,7 +67,7 @@ class MarMixin(object):
                 self.info("downloaded %s" % full_path)
             else:
                 self.info("found %s, skipping download" % full_path)
-            self.chmod(full_path, 0755)
+            self.chmod(full_path, 0o755)
 
     def _temp_mar_base_dir(self):
         """a base dir for unpacking mars"""
diff --git a/testing/mozharness/mozharness/mozilla/mock.py b/testing/mozharness/mozharness/mozilla/mock.py
index f8587c0d66..b9684fef8f 100644
--- a/testing/mozharness/mozharness/mozilla/mock.py
+++ b/testing/mozharness/mozharness/mozilla/mock.py
@@ -101,7 +101,7 @@ class MockMixin(object):
             cmd += ['--unpriv']
         cmd += ['--shell']
 
-        if not isinstance(command, basestring):
+        if not isinstance(command, str):
             command = subprocess.list2cmdline(command)
 
         # XXX - Hack - gets around AB_CD=%(locale)s type arguments
diff --git a/testing/mozharness/mozharness/mozilla/proxxy.py b/testing/mozharness/mozharness/mozilla/proxxy.py
index b9f14d5f2c..d0028a3f43 100644
--- a/testing/mozharness/mozharness/mozilla/proxxy.py
+++ b/testing/mozharness/mozharness/mozilla/proxxy.py
@@ -2,7 +2,7 @@
    proxxy instances (if available). The goal of Proxxy is to lower the traffic
    from the cloud to internal servers.
 """
-import urlparse
+import six.moves.urllib.parse
 import socket
 from mozharness.base.log import INFO, ERROR, LogMixin
 from mozharness.base.script import ScriptMixin
@@ -67,7 +67,7 @@ class Proxxy(ScriptMixin, LogMixin):
         proxxy_urls = config.get('urls', [])
         proxxy_instances = config.get('instances', [])
 
-        url_parts = urlparse.urlsplit(url)
+        url_parts = six.moves.urllib.parse.urlsplit(url)
         url_path = url_parts.path
         if url_parts.query:
             url_path += "?" + url_parts.query
diff --git a/testing/mozharness/mozharness/mozilla/release.py b/testing/mozharness/mozharness/mozilla/release.py
index 52a84cdba3..966db77a62 100755
--- a/testing/mozharness/mozharness/mozilla/release.py
+++ b/testing/mozharness/mozharness/mozilla/release.py
@@ -9,7 +9,27 @@
 """
 
 import os
-from distutils.version import LooseVersion, StrictVersion
+import re
+class LooseVersion:
+    """Simple version comparison (replacement for distutils.version.LooseVersion)."""
+    def __init__(self, vstring):
+        self.vstring = vstring
+        self.version = [int(x) if x.isdigit() else x for x in re.split(r'[.\-]', vstring)]
+    def __str__(self): return self.vstring
+    def __repr__(self): return "LooseVersion('%s')" % self.vstring
+    def _cmp(self, other):
+        if not isinstance(other, LooseVersion):
+            other = LooseVersion(str(other))
+        try:
+            if self.version == other.version: return 0
+            if self.version < other.version: return -1
+            return 1
+        except TypeError: return -1
+    def __lt__(self, o): return self._cmp(o) < 0
+    def __le__(self, o): return self._cmp(o) <= 0
+    def __eq__(self, o): return self._cmp(o) == 0
+    def __ge__(self, o): return self._cmp(o) >= 0
+    def __gt__(self, o): return self._cmp(o) > 0, StrictVersion
 
 from mozharness.base.config import parse_config_file
 
diff --git a/testing/mozharness/mozharness/mozilla/repo_manupulation.py b/testing/mozharness/mozharness/mozilla/repo_manupulation.py
index a2dfc46a2f..80c68ed182 100644
--- a/testing/mozharness/mozharness/mozilla/repo_manupulation.py
+++ b/testing/mozharness/mozharness/mozilla/repo_manupulation.py
@@ -114,7 +114,7 @@ class MercurialRepoManipulationMixin(object):
 
     def hg_tag(self, cwd, tags, user=None, message=None, revision=None,
                force=None, halt_on_failure=True):
-        if isinstance(tags, basestring):
+        if isinstance(tags, str):
             tags = [tags]
         cmd = self.query_exe('hg', return_type='list') + ['tag']
         if not message:
diff --git a/testing/mozharness/mozharness/mozilla/secrets.py b/testing/mozharness/mozharness/mozilla/secrets.py
index d40964bd67..164679e5fb 100644
--- a/testing/mozharness/mozharness/mozilla/secrets.py
+++ b/testing/mozharness/mozharness/mozilla/secrets.py
@@ -9,7 +9,7 @@
 
 import os
 import mozharness
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import json
 from mozharness.base.log import ERROR
 
@@ -22,7 +22,7 @@ class SecretsMixin(object):
         # within a taskcluster task.  Outside of that environment, do not
         # use this action.
         url = "http://taskcluster/secrets/v1/secret/" + secret_name
-        res = urllib2.urlopen(url)
+        res = six.moves.urllib.request.urlopen(url)
         if res.getcode() != 200:
             self.fatal("Error fetching from secrets API:" + res.read())
 
diff --git a/testing/mozharness/mozharness/mozilla/structuredlog.py b/testing/mozharness/mozharness/mozilla/structuredlog.py
index d87c5ebdc3..0d65ac8e79 100644
--- a/testing/mozharness/mozharness/mozilla/structuredlog.py
+++ b/testing/mozharness/mozharness/mozilla/structuredlog.py
@@ -111,7 +111,7 @@ class StructuredOutputParser(OutputParser):
             'suite_end': 'No suite end message was emitted by this harness.',
             'test_end': 'No checks run.',
         }
-        for action, diagnostic_message in required_actions.iteritems():
+        for action, diagnostic_message in required_actions.items():
             if action not in summary.action_counts:
                 self.log(diagnostic_message, ERROR)
                 self.update_levels(*error_pair)
diff --git a/testing/mozharness/mozharness/mozilla/taskcluster_helper.py b/testing/mozharness/mozharness/mozilla/taskcluster_helper.py
index 6921b8938d..c2b383fa15 100644
--- a/testing/mozharness/mozharness/mozilla/taskcluster_helper.py
+++ b/testing/mozharness/mozharness/mozilla/taskcluster_helper.py
@@ -3,7 +3,7 @@
 """
 import os
 from datetime import datetime, timedelta
-from urlparse import urljoin
+from urllib.parse import urljoin
 
 from mozharness.base.log import LogMixin
 
diff --git a/testing/mozharness/mozharness/mozilla/testing/device.py b/testing/mozharness/mozharness/mozilla/testing/device.py
index fea43ba20e..fe0b0a1dc4 100644
--- a/testing/mozharness/mozharness/mozilla/testing/device.py
+++ b/testing/mozharness/mozharness/mozilla/testing/device.py
@@ -438,7 +438,7 @@ class SUTDeviceHandler(BaseDeviceHandler):
             self.devicemanager = DeviceManagerSUT(c['device_ip'])
             # TODO configurable?
             self.devicemanager.debug = c.get('devicemanager_debug_level', 0)
-        except ImportError, e:
+        except ImportError as e:
             self.fatal("Can't import DeviceManagerSUT! %s\nDid you check out talos?" % str(e))
         return self.devicemanager
 
@@ -524,7 +524,7 @@ class SUTDeviceHandler(BaseDeviceHandler):
         try:
             dm.sendCMD(['settime %s' % s])
             return True
-        except self.DMError, e:
+        except self.DMError as e:
             self.add_device_flag(DEVICE_CANT_SET_TIME)
             self.fatal("Exception while setting device time: %s" % str(e))
 
@@ -564,7 +564,7 @@ class SUTDeviceHandler(BaseDeviceHandler):
                 self.info(repr(dm.getInfo('memory')))
                 self.info(repr(dm.getInfo('uptime')))
                 self.info(repr(dm.sendCMD(['exec su -c "logcat -d -v time *:W"'])))
-            except Exception, e:
+            except Exception as e:
                 self.info("Exception hit while trying to run logcat: %s" % str(e))
                 self.fatal("Remote Device Error: can't run logcat")
         except self.DMError:
@@ -676,7 +676,7 @@ device_config_options = [[
     {"action": "store",
      "type": "choice",
      "dest": "device_protocol",
-     "choices": DEVICE_PROTOCOL_DICT.keys(),
+     "choices": list(DEVICE_PROTOCOL_DICT.keys()),
      "help": "Specify the device communication protocol."
      }
 ], [
diff --git a/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
index b1874fc138..a99dc00dc9 100644
--- a/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
+++ b/testing/mozharness/mozharness/mozilla/testing/firefox_media_tests.py
@@ -8,7 +8,7 @@
 import copy
 import os
 import re
-import urlparse
+import six.moves.urllib.parse
 
 from mozharness.base.log import ERROR, WARNING
 from mozharness.base.script import PreScriptAction
@@ -257,7 +257,7 @@ class FirefoxMediaTestsBase(TestingMixin, VCSToolsScript):
             dirs = self.query_abs_dirs()
             manifest_path = os.path.join(dirs['abs_work_dir'], 'releng.manifest')
             try:
-                self.download_file(urlparse.urljoin(url_base, tooltool_manifest),
+                self.download_file(six.moves.urllib.parse.urljoin(url_base, tooltool_manifest),
                                    manifest_path)
             except Exception as e:
                 self.fatal('Download of tooltool manifest file failed: %s' % e.message)
diff --git a/testing/mozharness/mozharness/mozilla/testing/mozpool.py b/testing/mozharness/mozharness/mozilla/testing/mozpool.py
index f9da6c1908..74061ed934 100644
--- a/testing/mozharness/mozharness/mozilla/testing/mozpool.py
+++ b/testing/mozharness/mozharness/mozilla/testing/mozpool.py
@@ -48,7 +48,7 @@ class MozpoolMixin(object):
                 self.MozpoolException = MozpoolException
                 self.MozpoolConflictException = MozpoolConflictException
                 self.mozpool_handler = MozpoolHandler(self.mozpool_api_url, log_obj=self)
-            except ImportError, e:
+            except ImportError as e:
                 self.fatal("Can't instantiate MozpoolHandler until mozpoolclient python "
                            "package is installed! (VirtualenvMixin?): \n%s" % str(e))
             return self.mozpool_handler
@@ -66,7 +66,7 @@ class MozpoolMixin(object):
                 break
             except self.MozpoolConflictException:
                 self.warning("Device unavailable. Retry#%i.." % retry)
-            except self.MozpoolException, e:
+            except self.MozpoolException as e:
                 self.buildbot_status(TBPL_RETRY)
                 self.fatal("We could not request the device: %s" % str(e))
 
@@ -87,7 +87,7 @@ class MozpoolMixin(object):
                 break
             except self.MozpoolConflictException:
                 self.warning("Device unavailable. Retry#%i.." % retry)
-            except self.MozpoolException, e:
+            except self.MozpoolException as e:
                 self.buildbot_status(TBPL_RETRY)
                 self.fatal("We could not request the device: %s" % str(e))
 
diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py
index 73f384ce7a..2af816095c 100755
--- a/testing/mozharness/mozharness/mozilla/testing/talos.py
+++ b/testing/mozharness/mozharness/mozilla/testing/talos.py
@@ -258,7 +258,7 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin):
         kw_options.update(kw)
         # talos expects tests to be in the format (e.g.) 'ts:tp5:tsvg'
         tests = kw_options.get('activeTests')
-        if tests and not isinstance(tests, basestring):
+        if tests and not isinstance(tests, str):
             tests = ':'.join(tests)  # Talos expects this format
             kw_options['activeTests'] = tests
         for key, value in kw_options.items():
diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py
index 2ab2b7e43a..5fd4b75178 100755
--- a/testing/mozharness/mozharness/mozilla/testing/testbase.py
+++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py
@@ -10,7 +10,7 @@ import os
 import platform
 import pprint
 import re
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import json
 import socket
 
@@ -30,6 +30,7 @@ from mozharness.mozilla.testing.try_tools import TryToolsMixin, try_config_optio
 from mozharness.mozilla.tooltool import TooltoolMixin
 
 from mozharness.lib.python.authentication import get_credentials
+import six
 
 INSTALLER_SUFFIXES = ('.apk',  # Android
                       '.tar.bz2', '.tar.gz',  # Linux
@@ -258,7 +259,7 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin,
         if c.get("test_packages_url"):
             c["test_packages_url"] = _replace_url(c["test_packages_url"], c["replace_urls"])
 
-        for key, value in self.config.iteritems():
+        for key, value in self.config.items():
             if type(value) == str and value.startswith("http"):
                 self.config[key] = _replace_url(value, c["replace_urls"])
 
@@ -281,19 +282,19 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin,
 
             self.https_username, self.https_password = get_credentials()
             # This creates a password manager
-            passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
+            passman = six.moves.urllib.request.HTTPPasswordMgrWithDefaultRealm()
             # Because we have put None at the start it will use this username/password combination from here on
             passman.add_password(None, url, self.https_username, self.https_password)
-            authhandler = urllib2.HTTPBasicAuthHandler(passman)
+            authhandler = six.moves.urllib.request.HTTPBasicAuthHandler(passman)
 
-            return urllib2.build_opener(authhandler).open(url, **kwargs)
+            return six.moves.urllib.request.build_opener(authhandler).open(url, **kwargs)
 
         # If we have the developer_run flag enabled then we will switch
         # URLs to the right place and enable http authentication
         if "developer_config.py" in self.config["config_files"]:
             return _urlopen_basic_auth(url, **kwargs)
         else:
-            return urllib2.urlopen(url, **kwargs)
+            return six.moves.urllib.request.urlopen(url, **kwargs)
 
     # read_buildbot_config is in BuildbotMixin.
 
@@ -310,7 +311,7 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin,
             if c.get("require_test_zip") and not self.test_url:
                 expected_length = [2, 3]
             if buildbot_prop_branch.startswith('gaia-try'):
-                expected_length = range(1, 1000)
+                expected_length = list(range(1, 1000))
             actual_length = len(files)
             if actual_length not in expected_length:
                 self.fatal("Unexpected number of files in buildbot config %s.\nExpected these number(s) of files: %s, but got: %d" %
@@ -331,7 +332,7 @@ class TestingMixin(VirtualenvMixin, BuildbotMixin, ResourceMonitoringMixin,
                     if not self.installer_url:
                         self.installer_url = str(f['name'])
                         self.info("Found installer url %s." % self.installer_url)
-        except IndexError, e:
+        except IndexError as e:
             self.error(str(e))
 
     def find_artifacts_from_taskcluster(self):
@@ -734,7 +735,7 @@ Did you run with --create-virtualenv? Is mozinstall in virtualenv_modules?""")
 
         if os.path.exists(abs_nodejs_path):
             if self.platform_name() not in ('win32', 'win64'):
-                self.chmod(abs_nodejs_path, 0755)
+                self.chmod(abs_nodejs_path, 0o755)
             self.nodejs_path = abs_nodejs_path
         else:
             self.warning("nodejs path was given but couldn't be found. Tried looking in '%s'" % abs_nodejs_path)
@@ -774,7 +775,7 @@ Did you run with --create-virtualenv? Is mozinstall in virtualenv_modules?""")
             abs_minidump_path = os.path.join(dirs['abs_work_dir'],
                                              minidump_stackwalk_path)
             if os.path.exists(abs_minidump_path):
-                self.chmod(abs_minidump_path, 0755)
+                self.chmod(abs_minidump_path, 0o755)
                 self.minidump_stackwalk_path = abs_minidump_path
             else:
                 self.warning("minidump stackwalk path was given but couldn't be found. "
diff --git a/testing/mozharness/mozharness/mozilla/testing/try_tools.py b/testing/mozharness/mozharness/mozilla/testing/try_tools.py
index 3708e71db6..85d44be731 100644
--- a/testing/mozharness/mozharness/mozilla/testing/try_tools.py
+++ b/testing/mozharness/mozharness/mozilla/testing/try_tools.py
@@ -188,7 +188,7 @@ class TryToolsMixin(TransferMixin):
                 return label_dict[val]
             return '--%s' % val.replace('_', '-')
 
-        for label, (opts, _) in self.known_try_arguments.iteritems():
+        for label, (opts, _) in self.known_try_arguments.items():
             if 'action' in opts and opts['action'] not in ('append', 'store',
                                                            'store_true', 'store_false'):
                 self.fatal('Try syntax does not support passing custom or store_const '
@@ -207,7 +207,7 @@ class TryToolsMixin(TransferMixin):
         # This is a pretty hacky way to echo arguments down to the harness.
         # Hopefully this can be improved once we have a configuration system
         # in tree for harnesses that relies less on a command line.
-        for arg, value in vars(args).iteritems():
+        for arg, value in vars(args.items()):
             if value:
                 label = label_from_val(arg)
                 _, flavors = self.known_try_arguments[label]
diff --git a/testing/mozharness/mozharness/mozilla/tooltool.py b/testing/mozharness/mozharness/mozilla/tooltool.py
index 0bd98e0a26..2e65b36b67 100644
--- a/testing/mozharness/mozharness/mozilla/tooltool.py
+++ b/testing/mozharness/mozharness/mozilla/tooltool.py
@@ -115,7 +115,7 @@ class TooltoolMixin(object):
         self.download_file(TOOLTOOL_PY_URL, file_path)
         if not os.path.exists(file_path):
             self.fatal("We can't get tooltool.py")
-        self.chmod(file_path, 0755)
+        self.chmod(file_path, 0o755)
         return file_path
 
     def create_tooltool_manifest(self, contents, path=None):
diff --git a/testing/mozharness/mozharness/mozilla/updates/balrog.py b/testing/mozharness/mozharness/mozilla/updates/balrog.py
index 26253283cf..fe0fc814df 100644
--- a/testing/mozharness/mozharness/mozilla/updates/balrog.py
+++ b/testing/mozharness/mozharness/mozilla/updates/balrog.py
@@ -20,13 +20,13 @@ class BalrogMixin(object):
         )
 
         if self.buildbot_config and "properties" in self.buildbot_config:
-            buildbot_properties = self.buildbot_config["properties"].items()
+            buildbot_properties = list(self.buildbot_config["properties"].items())
         else:
             buildbot_properties = []
 
         balrog_props = dict(properties=dict(chain(
             buildbot_properties,
-            self.buildbot_properties.items(),
+            list(self.buildbot_properties.items()),
         )))
         if self.config.get('balrog_platform'):
             balrog_props["properties"]["platform"] = self.config['balrog_platform']
diff --git a/testing/mozharness/mozharness/mozilla/vcstools.py b/testing/mozharness/mozharness/mozilla/vcstools.py
index b73a4767d8..1c11fdc842 100644
--- a/testing/mozharness/mozharness/mozilla/vcstools.py
+++ b/testing/mozharness/mozharness/mozilla/vcstools.py
@@ -34,7 +34,7 @@ class VCSToolsScript(VCSScript):
                         parent_dir=os.path.dirname(file_path),
                         create_parent_dir=True,
                     )
-                    self.chmod(file_path, 0755)
+                    self.chmod(file_path, 0o755)
         else:
             # We simply verify that everything is in order
             # or if the user forgot to specify developer mode
diff --git a/testing/mozharness/mozinfo/__init__.py b/testing/mozharness/mozinfo/__init__.py
index 904dfef71a..e45d71ff87 100644
--- a/testing/mozharness/mozinfo/__init__.py
+++ b/testing/mozharness/mozinfo/__init__.py
@@ -51,6 +51,6 @@ Module variables:
 
 """
 
-import mozinfo
-from mozinfo import *
+from . import mozinfo
+from .mozinfo import *
 __all__ = mozinfo.__all__
diff --git a/testing/mozharness/mozinfo/mozinfo.py b/testing/mozharness/mozinfo/mozinfo.py
index 718e1a9d7a..7aa897a401 100755
--- a/testing/mozharness/mozinfo/mozinfo.py
+++ b/testing/mozharness/mozinfo/mozinfo.py
@@ -8,6 +8,7 @@
 # linux) to the information; I certainly wouldn't want anyone parsing this
 # information and having behaviour depend on it
 
+from __future__ import print_function
 import json
 import os
 import platform
@@ -111,7 +112,7 @@ def update(new_info):
                      to a json file containing the new info.
     """
 
-    if isinstance(new_info, basestring):
+    if isinstance(new_info, str):
         f = mozfile.load(new_info)
         new_info = json.loads(f.read())
         f.close()
@@ -161,7 +162,7 @@ def find_and_update_from_json(*dirs):
 update({})
 
 # exports
-__all__ = info.keys()
+__all__ = list(info.keys())
 __all__ += ['is' + os_name.title() for os_name in choices['os']]
 __all__ += [
     'info',
@@ -187,7 +188,7 @@ def main(args=None):
     if args:
         for arg in args:
             if _os.path.exists(arg):
-                string = file(arg).read()
+                string = open(arg).read()
             else:
                 string = arg
             update(json.loads(string))
@@ -196,14 +197,14 @@ def main(args=None):
     flag = False
     for key, value in options.__dict__.items():
         if value is True:
-            print '%s choices: %s' % (key, ' '.join([str(choice)
-                                                     for choice in choices[key]]))
+            print('%s choices: %s' % (key, ' '.join([str(choice)
+                                                     for choice in choices[key]])))
             flag = True
     if flag: return
 
     # otherwise, print out all info
     for key, value in info.items():
-        print '%s: %s' % (key, value)
+        print('%s: %s' % (key, value))
 
 if __name__ == '__main__':
     main()
diff --git a/testing/mozharness/mozprocess/__init__.py b/testing/mozharness/mozprocess/__init__.py
index 6f4ae49450..02935d078d 100644
--- a/testing/mozharness/mozprocess/__init__.py
+++ b/testing/mozharness/mozprocess/__init__.py
@@ -2,4 +2,4 @@
 # 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 processhandler import *
+from .processhandler import *
diff --git a/testing/mozharness/mozprocess/pid.py b/testing/mozharness/mozprocess/pid.py
index d1f0d93368..d9a943d560 100755
--- a/testing/mozharness/mozprocess/pid.py
+++ b/testing/mozharness/mozprocess/pid.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import os
 import mozinfo
 import shlex
@@ -75,7 +76,7 @@ def get_pids(name):
 
     if mozinfo.isWin:
         # use the windows-specific implementation
-        import wpk
+        from . import wpk
         return wpk.get_pids(name)
     else:
         return [pid for pid,_ in running_processes(name)]
@@ -85,4 +86,4 @@ if __name__ == '__main__':
     for i in sys.argv[1:]:
         pids.update(get_pids(i))
     for i in sorted(pids):
-        print i
+        print(i)
diff --git a/testing/mozharness/mozprocess/processhandler.py b/testing/mozharness/mozprocess/processhandler.py
index b89e17eb03..71c0d73592 100644
--- a/testing/mozharness/mozprocess/processhandler.py
+++ b/testing/mozharness/mozprocess/processhandler.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import select
 import signal
@@ -10,7 +11,7 @@ import sys
 import threading
 import time
 import traceback
-from Queue import Queue
+from queue import Queue
 from datetime import datetime, timedelta
 __all__ = ['ProcessHandlerMixin', 'ProcessHandler']
 
@@ -24,8 +25,8 @@ isPosix = os.name == "posix" # includes MacOS X
 if isWin:
     import ctypes, ctypes.wintypes, msvcrt
     from ctypes import sizeof, addressof, c_ulong, byref, POINTER, WinError, c_longlong
-    import winprocess
-    from qijo import JobObjectAssociateCompletionPortInformation,\
+    from . import winprocess
+    from .qijo import JobObjectAssociateCompletionPortInformation,\
     JOBOBJECT_ASSOCIATE_COMPLETION_PORT, JobObjectExtendedLimitInformation,\
     JOBOBJECT_BASIC_LIMIT_INFORMATION, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS
 
@@ -94,17 +95,17 @@ class ProcessHandlerMixin(object):
                                           preexec_fn, close_fds,
                                           shell, cwd, env,
                                           universal_newlines, startupinfo, creationflags)
-            except OSError, e:
-                print >> sys.stderr, args
+            except OSError as e:
+                print(args, file=sys.stderr)
                 raise
 
-        def __del__(self, _maxint=sys.maxint):
+        def __del__(self, _maxint=sys.maxsize):
             if isWin:
                 if self._handle:
                     if hasattr(self, '_internal_poll'):
                         self._internal_poll(_deadstate=_maxint)
                     else:
-                        self.poll(_deadstate=sys.maxint)
+                        self.poll(_deadstate=sys.maxsize)
                 if self._handle or self._job or self._io_port:
                     self._cleanup()
             else:
@@ -131,10 +132,10 @@ class ProcessHandlerMixin(object):
                 if not self._ignore_children:
                     try:
                         os.killpg(self.pid, sig)
-                    except BaseException, e:
+                    except BaseException as e:
                         if getattr(e, "errno", None) != 3:
                             # Error 3 is "no such process", which is ok
-                            print >> sys.stdout, "Could not kill process, could not find pid: %s, assuming it's already dead" % self.pid
+                            print("Could not kill process, could not find pid: %s, assuming it's already dead" % self.pid, file=sys.stdout)
                 else:
                     os.kill(self.pid, sig)
                 self.returncode = -sig
@@ -174,7 +175,7 @@ class ProcessHandlerMixin(object):
                      p2cread, p2cwrite,
                      c2pread, c2pwrite,
                      errread, errwrite) = args_tuple
-                if not isinstance(args, basestring):
+                if not isinstance(args, str):
                     args = subprocess.list2cmdline(args)
 
                 # Always or in the create new process group
@@ -201,7 +202,7 @@ class ProcessHandlerMixin(object):
                 if not canCreateJob and not self._ignore_children:
                     # We can't create job objects AND the user wanted us to
                     # Warn the user about this.
-                    print >> sys.stderr, "ProcessManager UNABLE to use job objects to manage child processes"
+                    print("ProcessManager UNABLE to use job objects to manage child processes", file=sys.stderr)
 
                 # set process creation flags
                 creationflags |= winprocess.CREATE_SUSPENDED
@@ -211,7 +212,7 @@ class ProcessHandlerMixin(object):
                 else:
                     # Since we've warned, we just log info here to inform you
                     # of the consequence of setting ignore_children = True
-                    print "ProcessManager NOT managing child processes"
+                    print("ProcessManager NOT managing child processes")
 
                 # create the process
                 hp, ht, pid, tid = winprocess.CreateProcess(
@@ -283,10 +284,10 @@ class ProcessHandlerMixin(object):
                         # Spin up our thread for managing the IO Completion Port
                         self._procmgrthread = threading.Thread(target = self._procmgr)
                     except:
-                        print >> sys.stderr, """Exception trying to use job objects;
-falling back to not using job objects for managing child processes"""
+                        print("""Exception trying to use job objects;
+falling back to not using job objects for managing child processes""", file=sys.stderr)
                         tb = traceback.format_exc()
-                        print >> sys.stderr, tb
+                        print(tb, file=sys.stderr)
                         # Ensure no dangling handles left behind
                         self._cleanup_job_io_port()
                 else:
@@ -318,7 +319,7 @@ falling back to not using job objects for managing child processes"""
                 countdowntokill = 0
 
                 if MOZPROCESS_DEBUG:
-                    print "DBG::MOZPROC Self.pid value is: %s" % self.pid
+                    print("DBG::MOZPROC Self.pid value is: %s" % self.pid)
 
                 while True:
                     msgid = c_ulong(0)
@@ -340,9 +341,9 @@ falling back to not using job objects for managing child processes"""
                         # don't want to mistake that situation for the situation of an unexpected
                         # parent abort (which is what we're looking for here).
                         if diff.seconds > self.MAX_IOCOMPLETION_PORT_NOTIFICATION_DELAY:
-                            print >> sys.stderr, "Parent process %s exited with children alive:" % self.pid
-                            print >> sys.stderr, "PIDS: %s" %  ', '.join([str(i) for i in self._spawned_procs])
-                            print >> sys.stderr, "Attempting to kill them..."
+                            print("Parent process %s exited with children alive:" % self.pid, file=sys.stderr)
+                            print("PIDS: %s" %  ', '.join([str(i) for i in self._spawned_procs]), file=sys.stderr)
+                            print("Attempting to kill them...", file=sys.stderr)
                             self.kill()
                             self._process_events.put({self.pid: 'FINISHED'})
 
@@ -351,19 +352,19 @@ falling back to not using job objects for managing child processes"""
                         errcode = winprocess.GetLastError()
                         if errcode == winprocess.ERROR_ABANDONED_WAIT_0:
                             # Then something has killed the port, break the loop
-                            print >> sys.stderr, "IO Completion Port unexpectedly closed"
+                            print("IO Completion Port unexpectedly closed", file=sys.stderr)
                             break
                         elif errcode == winprocess.WAIT_TIMEOUT:
                             # Timeouts are expected, just keep on polling
                             continue
                         else:
-                            print >> sys.stderr, "Error Code %s trying to query IO Completion Port, exiting" % errcode
+                            print("Error Code %s trying to query IO Completion Port, exiting" % errcode, file=sys.stderr)
                             raise WinError(errcode)
                             break
 
                     if compkey.value == winprocess.COMPKEY_TERMINATE.value:
                         if MOZPROCESS_DEBUG:
-                            print "DBG::MOZPROC compkeyterminate detected"
+                            print("DBG::MOZPROC compkeyterminate detected")
                         # Then we're done
                         break
 
@@ -373,7 +374,7 @@ falling back to not using job objects for managing child processes"""
                             # No processes left, time to shut down
                             # Signal anyone waiting on us that it is safe to shut down
                             if MOZPROCESS_DEBUG:
-                                print "DBG::MOZPROC job object msg active processes zero"
+                                print("DBG::MOZPROC job object msg active processes zero")
                             self._process_events.put({self.pid: 'FINISHED'})
                             break
                         elif msgid.value == winprocess.JOB_OBJECT_MSG_NEW_PROCESS:
@@ -383,10 +384,10 @@ falling back to not using job objects for managing child processes"""
                             if pid.value != self.pid:
                                 self._spawned_procs[pid.value] = 1
                                 if MOZPROCESS_DEBUG:
-                                    print "DBG::MOZPROC new process detected with pid value: %s" % pid.value
+                                    print("DBG::MOZPROC new process detected with pid value: %s" % pid.value)
                         elif msgid.value == winprocess.JOB_OBJECT_MSG_EXIT_PROCESS:
                             if MOZPROCESS_DEBUG:
-                                print "DBG::MOZPROC process id %s exited normally" % pid.value
+                                print("DBG::MOZPROC process id %s exited normally" % pid.value)
                             # One process exited normally
                             if pid.value == self.pid and len(self._spawned_procs) > 0:
                                 # Parent process dying, start countdown timer
@@ -397,7 +398,7 @@ falling back to not using job objects for managing child processes"""
                         elif msgid.value == winprocess.JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS:
                             # One process existed abnormally
                             if MOZPROCESS_DEBUG:
-                                print "DBG::MOZPROC process id %s existed abnormally" % pid.value
+                                print("DBG::MOZPROC process id %s existed abnormally" % pid.value)
                             if pid.value == self.pid and len(self._spawned_procs) > 0:
                                 # Parent process dying, start countdown timer
                                 countdowntokill = datetime.now()
@@ -407,7 +408,7 @@ falling back to not using job objects for managing child processes"""
                         else:
                             # We don't care about anything else
                             if MOZPROCESS_DEBUG:
-                                print "DBG::MOZPROC We got a message %s" % msgid.value
+                                print("DBG::MOZPROC We got a message %s" % msgid.value)
                             pass
 
             def _wait(self):
@@ -457,7 +458,7 @@ falling back to not using job objects for managing child processes"""
                     # is call waitforsingleobject and hope for the best
 
                     if MOZPROCESS_DEBUG and not self._ignore_children:
-                        print "DBG::MOZPROC NOT USING JOB OBJECTS!!!"
+                        print("DBG::MOZPROC NOT USING JOB OBJECTS!!!")
                     # First, make sure we have not already ended
                     if self.returncode != winprocess.STILL_ACTIVE:
                         self._cleanup()
@@ -469,11 +470,11 @@ falling back to not using job objects for managing child processes"""
 
                     if rc == winprocess.WAIT_TIMEOUT:
                         # The process isn't dead, so kill it
-                        print "Timed out waiting for process to close, attempting TerminateProcess"
+                        print("Timed out waiting for process to close, attempting TerminateProcess")
                         self.kill()
                     elif rc == winprocess.WAIT_OBJECT_0:
                         # We caught WAIT_OBJECT_0, which indicates all is well
-                        print "Single process terminated successfully"
+                        print("Single process terminated successfully")
                         self.returncode = winprocess.GetExitCodeProcess(self._handle)
                     else:
                         # An error occured we should probably throw
@@ -546,11 +547,11 @@ falling back to not using job objects for managing child processes"""
                         if status > 255:
                             return status >> 8
                         return -status
-                    except OSError, e:
+                    except OSError as e:
                         if getattr(e, "errno", None) != 10:
                             # Error 10 is "no child process", which could indicate normal
                             # close
-                            print >> sys.stderr, "Encountered error waiting for pid to close: %s" % e
+                            print("Encountered error waiting for pid to close: %s" % e, file=sys.stderr)
                             raise
                         return 0
 
@@ -564,7 +565,7 @@ falling back to not using job objects for managing child processes"""
 
         else:
             # An unrecognized platform, we will call the base class for everything
-            print >> sys.stderr, "Unrecognized platform, process groups may not be managed properly"
+            print("Unrecognized platform, process groups may not be managed properly", file=sys.stderr)
 
             def _wait(self):
                 self.returncode = subprocess.Popen.wait(self)
@@ -672,7 +673,7 @@ falling back to not using job objects for managing child processes"""
         except AttributeError:
             # Try to print a relevant error message.
             if not self.proc:
-                print >> sys.stderr, "Unable to kill Process because call to ProcessHandler constructor failed."
+                print("Unable to kill Process because call to ProcessHandler constructor failed.", file=sys.stderr)
             else:
                 raise
 
@@ -782,8 +783,8 @@ falling back to not using job objects for managing child processes"""
 
     # TODO Remove this method when consumers have been fixed
     def waitForFinish(self, timeout=None):
-        print >> sys.stderr, "MOZPROCESS WARNING: ProcessHandler.waitForFinish() is deprecated, " \
-                             "use ProcessHandler.wait() instead"
+        print("MOZPROCESS WARNING: ProcessHandler.waitForFinish() is deprecated, " \
+                             "use ProcessHandler.wait() instead", file=sys.stderr)
         return self.wait(timeout=timeout)
 
 
@@ -855,7 +856,7 @@ falling back to not using job objects for managing child processes"""
 ### these should be callables that take the output line
 
 def print_output(line):
-    print line
+    print(line)
 
 class StoreOutput(object):
     """accumulate stdout"""
@@ -875,7 +876,7 @@ class LogOutput(object):
 
     def __call__(self, line):
         if self.file is None:
-            self.file = file(self.filename, 'a')
+            self.file = open(self.filename, 'a')
         self.file.write(line + '\n')
         self.file.flush()
 
diff --git a/testing/mozharness/mozprocess/qijo.py b/testing/mozharness/mozprocess/qijo.py
index 1ac88430ce..1da1cfcee5 100644
--- a/testing/mozharness/mozprocess/qijo.py
+++ b/testing/mozharness/mozprocess/qijo.py
@@ -77,7 +77,7 @@ class JobObjectInfo(object):
                    9: JOBOBJECT_EXTENDED_LIMIT_INFORMATION
                    }
     def __init__(self, _class):
-        if isinstance(_class, basestring):
+        if isinstance(_class, str):
             assert _class in self.mapping, 'Class should be one of %s; you gave %s' % (self.mapping, _class)
             _class = self.mapping[_class]
         assert _class in self.structures, 'Class should be one of %s; you gave %s' % (self.structures, _class)
diff --git a/testing/mozharness/mozprocess/winprocess.py b/testing/mozharness/mozprocess/winprocess.py
index 6f3afc8de3..68a539216e 100644
--- a/testing/mozharness/mozprocess/winprocess.py
+++ b/testing/mozharness/mozprocess/winprocess.py
@@ -34,9 +34,10 @@
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+from __future__ import print_function
 from ctypes import c_void_p, POINTER, sizeof, Structure, Union, windll, WinError, WINFUNCTYPE, c_ulong
 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD, ULONG
-from qijo import QueryInformationJobObject
+from .qijo import QueryInformationJobObject
 
 LPVOID = c_void_p
 LPBYTE = POINTER(BYTE)
@@ -140,7 +141,7 @@ class EnvironmentBlock:
             self._as_parameter_ = None
         else:
             values = ["%s=%s" % (key, value)
-                      for (key, value) in dict.iteritems()]
+                      for (key, value) in dict.items()]
             values.append("")
             self._as_parameter_ = LPCWSTR("\0".join(values))
 
@@ -426,32 +427,32 @@ def CanCreateJobObject():
 ### testing functions
 
 def parent():
-    print 'Starting parent'
+    print('Starting parent')
     currentProc = GetCurrentProcess()
     if IsProcessInJob(currentProc):
-        print >> sys.stderr, "You should not be in a job object to test"
+        print("You should not be in a job object to test", file=sys.stderr)
         sys.exit(1)
     assert CanCreateJobObject()
-    print 'File: %s' % __file__
+    print('File: %s' % __file__)
     command = [sys.executable, __file__, '-child']
-    print 'Running command: %s' % command
+    print('Running command: %s' % command)
     process = Popen(command)
     process.kill()
     code = process.returncode
-    print 'Child code: %s' % code
+    print('Child code: %s' % code)
     assert code == 127
         
 def child():
-    print 'Starting child'
+    print('Starting child')
     currentProc = GetCurrentProcess()
     injob = IsProcessInJob(currentProc)
-    print "Is in a job?: %s" % injob
+    print("Is in a job?: %s" % injob)
     can_create = CanCreateJobObject()
-    print 'Can create job?: %s' % can_create
+    print('Can create job?: %s' % can_create)
     process = Popen('c:\\windows\\notepad.exe')
     assert process._job
     jobinfo = QueryInformationJobObject(process._job, 'JobObjectExtendedLimitInformation')
-    print 'Job info: %s' % jobinfo
+    print('Job info: %s' % jobinfo)
     limitflags = jobinfo['BasicLimitInformation']['LimitFlags']
-    print 'LimitFlags: %s' % limitflags
+    print('LimitFlags: %s' % limitflags)
     process.kill()
diff --git a/testing/mozharness/scripts/android_emulator_unittest.py b/testing/mozharness/scripts/android_emulator_unittest.py
index 84c5447ed3..2f7a48bebc 100644
--- a/testing/mozharness/scripts/android_emulator_unittest.py
+++ b/testing/mozharness/scripts/android_emulator_unittest.py
@@ -298,7 +298,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin
                 telnet_ok = True
             else:
                 self.warning('Unable to connect to port %d' % port)
-        except socket.error, e:
+        except socket.error as e:
             self.info('Trying again after socket error: %s' % str(e))
             pass
         except EOFError:
@@ -398,7 +398,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin
             os.close(tmpfd)
             self.info("Taking screenshot with %s; saving to %s" % (utility, filename))
             subprocess.call([utility, filename], env=self.query_env())
-        except OSError, err:
+        except OSError as err:
             self.warning("Failed to take screenshot: %s" % err.strerror)
 
     def _query_package_name(self):
diff --git a/testing/mozharness/scripts/configtest.py b/testing/mozharness/scripts/configtest.py
index 5db684f0a7..baa15ed4c1 100755
--- a/testing/mozharness/scripts/configtest.py
+++ b/testing/mozharness/scripts/configtest.py
@@ -118,7 +118,7 @@ class ConfigTest(BaseScript):
                 global_dict = {}
                 local_dict = {}
                 try:
-                    execfile(config_file, global_dict, local_dict)
+                    exec(compile(open(config_file, "rb").read(), config_file, 'exec'), global_dict, local_dict)
                 except:
                     self.add_summary("%s is invalid python." % config_file,
                                      level="error")
diff --git a/testing/mozharness/scripts/desktop_l10n.py b/testing/mozharness/scripts/desktop_l10n.py
index 0626ce35b5..cbb7f6ba48 100755
--- a/testing/mozharness/scripts/desktop_l10n.py
+++ b/testing/mozharness/scripts/desktop_l10n.py
@@ -623,7 +623,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
 
         for repository in config['repos']:
             current_repo = {}
-            for key, value in repository.iteritems():
+            for key, value in repository.items():
                 try:
                     current_repo[key] = value % replace_dict
                 except TypeError:
@@ -1051,7 +1051,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
     def taskcluster_upload(self):
         auth = os.path.join(os.getcwd(), self.config['taskcluster_credentials_file'])
         credentials = {}
-        execfile(auth, credentials)
+        exec(compile(open(auth, "rb").read(), auth, 'exec'), credentials)
         client_id = credentials.get('taskcluster_clientId')
         access_token = credentials.get('taskcluster_accessToken')
         if not client_id or not access_token:
@@ -1095,7 +1095,7 @@ class DesktopSingleLocale(LocalesMixin, ReleaseMixin, MockMixin, BuildbotMixin,
             artifacts_task = artifacts_tc.get_task(artifacts_task_id)
             artifacts_tc.claim_task(artifacts_task)
 
-        for locale, files in self.upload_files.iteritems():
+        for locale, files in self.upload_files.items():
             self.info("Uploading files to S3 for locale '%s': %s" % (locale, files))
             routes = []
             for template in templates:
diff --git a/testing/mozharness/scripts/desktop_partner_repacks.py b/testing/mozharness/scripts/desktop_partner_repacks.py
index ff07dffc84..570675f811 100755
--- a/testing/mozharness/scripts/desktop_partner_repacks.py
+++ b/testing/mozharness/scripts/desktop_partner_repacks.py
@@ -162,7 +162,7 @@ class DesktopPartnerRepacks(ReleaseMixin, BuildbotMixin, PurgeMixin,
                                   error_level=FATAL)
         if not os.path.exists(repo):
             self.fatal("Unable to download repo tool.")
-        self.chmod(repo, 0755)
+        self.chmod(repo, 0o755)
         self.retry(self._repo_init,
                    args=(repo,),
                    error_level=FATAL,
diff --git a/testing/mozharness/scripts/desktop_unittest.py b/testing/mozharness/scripts/desktop_unittest.py
index b2e7545671..31bd3a808c 100755
--- a/testing/mozharness/scripts/desktop_unittest.py
+++ b/testing/mozharness/scripts/desktop_unittest.py
@@ -451,7 +451,7 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix
                 # suites gets a dict of everything from all_suites where a key
                 # is also in specified_suites
                 suites = dict((key, all_suites.get(key)) for key in
-                              specified_suites if key in all_suites.keys())
+                              specified_suites if key in list(all_suites.keys()))
         else:
             if c.get('run_all_suites'):  # needed if you dont specify any suites
                 suites = all_suites
diff --git a/testing/mozharness/scripts/firefox_ui_tests/update_release.py b/testing/mozharness/scripts/firefox_ui_tests/update_release.py
index f1ec816463..055dbbb749 100755
--- a/testing/mozharness/scripts/firefox_ui_tests/update_release.py
+++ b/testing/mozharness/scripts/firefox_ui_tests/update_release.py
@@ -10,7 +10,7 @@ import copy
 import os
 import pprint
 import sys
-import urllib
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 
 # load modules from parent dir
 sys.path.insert(1, os.path.dirname(os.path.dirname(sys.path[0])))
@@ -239,7 +239,7 @@ class ReleaseFirefoxUIUpdateTests(FirefoxUIUpdateTests):
                 # Determine from where to download the file
                 installer_url = '{server}/{fragment}'.format(
                     server=rel_info['ftp_server_from'],
-                    fragment=urllib.quote(rel_info['from'].replace('%locale%', locale))
+                    fragment=six.moves.urllib.parse.quote(rel_info['from'].replace('%locale%', locale))
                 )
                 installer_path = self.download_file(
                     url=installer_url,
diff --git a/testing/mozharness/scripts/gaia_unit.py b/testing/mozharness/scripts/gaia_unit.py
index 660643b742..8eac51b64a 100755
--- a/testing/mozharness/scripts/gaia_unit.py
+++ b/testing/mozharness/scripts/gaia_unit.py
@@ -5,6 +5,7 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 # ***** END LICENSE BLOCK *****
 
+from __future__ import print_function
 import os
 import sys
 import glob
@@ -68,7 +69,7 @@ class GaiaUnitTest(GaiaTest):
                     try:
                         disabled_tests = json.loads(m.read())
                     except:
-                        print "Error while decoding disabled.json; please make sure this file has valid JSON syntax."
+                        print("Error while decoding disabled.json; please make sure this file has valid JSON syntax.")
                         sys.exit(1)
 
                 # Construct a list of all tests
@@ -76,10 +77,10 @@ class GaiaUnitTest(GaiaTest):
                 for path in ('apps', 'tv_apps'):
                     test_root    = os.path.join(dirs['abs_gaia_dir'], path)
                     full_paths   = glob.glob(os.path.join(test_root, '*/test/unit/*_test.js'))
-                    unit_tests  += map(lambda x: os.path.relpath(x, test_root), full_paths)
+                    unit_tests  += [os.path.relpath(x, test_root) for x in full_paths]
 
                 # Remove the tests that are disabled
-                active_unit_tests = filter(lambda x: x not in disabled_tests, unit_tests)
+                active_unit_tests = [x for x in unit_tests if x not in disabled_tests]
 
                 # Chunk the list as requested
                 tests_to_run = subprocess.check_output(chunker + active_unit_tests).strip().split(' ')
diff --git a/testing/mozharness/scripts/merge_day/gecko_migration.py b/testing/mozharness/scripts/merge_day/gecko_migration.py
index 7208630e0f..7c178a97d4 100755
--- a/testing/mozharness/scripts/merge_day/gecko_migration.py
+++ b/testing/mozharness/scripts/merge_day/gecko_migration.py
@@ -531,7 +531,7 @@ class GeckoMigration(MercurialScript, BalrogMixin, VirtualenvMixin,
         revision = self.query_to_revision()
         # Horrible hack because our internal buildapi interface doesn't let us
         # actually do anything. Need to use the public one w/ auth.
-        username = raw_input("LDAP Username: ")
+        username = input("LDAP Username: ")
         password = getpass(prompt="LDAP Password: ")
         auth = (username, password)
         for builder in self.config["post_merge_builders"]:
diff --git a/testing/mozharness/scripts/mobile_l10n.py b/testing/mozharness/scripts/mobile_l10n.py
index cbac6fa678..048b4be1dd 100755
--- a/testing/mozharness/scripts/mobile_l10n.py
+++ b/testing/mozharness/scripts/mobile_l10n.py
@@ -510,7 +510,7 @@ class MobileSingleLocale(MockMixin, LocalesMixin, ReleaseMixin,
     def taskcluster_upload(self):
         auth = os.path.join(os.getcwd(), self.config['taskcluster_credentials_file'])
         credentials = {}
-        execfile(auth, credentials)
+        exec(compile(open(auth, "rb").read(), auth, 'exec'), credentials)
         client_id = credentials.get('taskcluster_clientId')
         access_token = credentials.get('taskcluster_accessToken')
         if not client_id or not access_token:
diff --git a/testing/mozharness/scripts/release/antivirus.py b/testing/mozharness/scripts/release/antivirus.py
index a28c3fd2f5..ebd95742e9 100644
--- a/testing/mozharness/scripts/release/antivirus.py
+++ b/testing/mozharness/scripts/release/antivirus.py
@@ -130,7 +130,7 @@ class AntivirusScan(BaseScript, VirtualenvMixin):
         from boto.s3.connection import S3Connection
         from boto.exception import S3CopyError, S3ResponseError
         from redo import retry
-        from httplib import HTTPException
+        from six.moves.http_client import HTTPException
 
         # suppress boto debug logging, it's too verbose with --loglevel=debug
         import logging
diff --git a/testing/mozharness/scripts/release/beet_mover.py b/testing/mozharness/scripts/release/beet_mover.py
index 0f3c187530..60b4d549b3 100755
--- a/testing/mozharness/scripts/release/beet_mover.py
+++ b/testing/mozharness/scripts/release/beet_mover.py
@@ -364,7 +364,7 @@ class BeetMover(BaseScript, VirtualenvMixin, object):
     def mime_fix(self):
         """ Add mimetypes for custom extensions """
         mimetypes.init()
-        map(lambda (ext, mime_type,): mimetypes.add_type(mime_type, ext), MIME_MAP.items())
+        list(map(lambda ext_mime_type: mimetypes.add_type(ext_mime_type[1], ext_mime_type[0]), list(MIME_MAP.items())))
 
 if __name__ == '__main__':
     beet_mover = BeetMover(pop_aws_auth_from_env())
diff --git a/testing/mozharness/scripts/release/generate-checksums.py b/testing/mozharness/scripts/release/generate-checksums.py
index 61a1c43d25..d05aab7bbf 100644
--- a/testing/mozharness/scripts/release/generate-checksums.py
+++ b/testing/mozharness/scripts/release/generate-checksums.py
@@ -204,7 +204,7 @@ class ChecksumsGenerator(BaseScript, VirtualenvMixin, SigningMixin, VCSMixin, Bu
         pool.map(worker, find_checksums_files())
 
         for c in raw_checksums:
-            for f, info in parse_checksums_file(c).iteritems():
+            for f, info in parse_checksums_file(c.items()):
                 for pattern in self.config["includes"]:
                     if re.search(pattern, f):
                         if f in self.checksums:
diff --git a/testing/mozharness/scripts/release/postrelease_bouncer_aliases.py b/testing/mozharness/scripts/release/postrelease_bouncer_aliases.py
index 78a60b4bc5..ac7eb8c662 100644
--- a/testing/mozharness/scripts/release/postrelease_bouncer_aliases.py
+++ b/testing/mozharness/scripts/release/postrelease_bouncer_aliases.py
@@ -91,10 +91,10 @@ class PostReleaseBouncerAliases(BaseScript, VirtualenvMixin, BuildbotMixin):
         credentials_file = os.path.join(os.getcwd(),
                                         self.config['credentials_file'])
         credentials = {}
-        execfile(credentials_file, credentials)
+        exec(compile(open(credentials_file, "rb").read(), credentials_file, 'exec'), credentials)
         auth = (credentials['tuxedoUsername'], credentials['tuxedoPassword'])
         version = self.config['version']
-        for product, info in self.config["products"].iteritems():
+        for product, info in self.config["products"].items():
             if "alias" in info:
                 product_template = info["product-name"]
                 related_product = product_template % {"version": version}
diff --git a/testing/mozharness/scripts/release/postrelease_mark_as_shipped.py b/testing/mozharness/scripts/release/postrelease_mark_as_shipped.py
index f84b5771cb..72df206fd1 100644
--- a/testing/mozharness/scripts/release/postrelease_mark_as_shipped.py
+++ b/testing/mozharness/scripts/release/postrelease_mark_as_shipped.py
@@ -90,7 +90,7 @@ class MarkReleaseAsShipped(BaseScript, VirtualenvMixin, BuildbotMixin):
         credentials_file = os.path.join(os.getcwd(),
                                         self.config["credentials_file"])
         credentials = {}
-        execfile(credentials_file, credentials)
+        exec(compile(open(credentials_file, "rb").read(), credentials_file, 'exec'), credentials)
         ship_it_credentials = credentials["ship_it_credentials"]
         auth = (self.config["ship_it_username"],
                 ship_it_credentials.get(self.config["ship_it_username"]))
diff --git a/testing/mozharness/scripts/release/uptake_monitoring.py b/testing/mozharness/scripts/release/uptake_monitoring.py
index 9ec24621f6..9cecaf92da 100644
--- a/testing/mozharness/scripts/release/uptake_monitoring.py
+++ b/testing/mozharness/scripts/release/uptake_monitoring.py
@@ -122,7 +122,7 @@ class UptakeMonitoring(BaseScript, VirtualenvMixin, BuildbotMixin):
         version = self.config["version"]
         dl = []
 
-        for product, info in self.config["products"].iteritems():
+        for product, info in self.config["products"].items():
             if info.get("check_uptake"):
                 product_template = info["product-name"]
                 related_product = product_template % {"version": version}
@@ -137,7 +137,7 @@ class UptakeMonitoring(BaseScript, VirtualenvMixin, BuildbotMixin):
                                                        related_product, bouncer_platform))
         # handle the partials as well
         prev_versions = self.config["partial_versions"]
-        for product, info in self.config["partials"].iteritems():
+        for product, info in self.config["partials"].items():
             if info.get("check_uptake"):
                 product_template = info["product-name"]
                 for prev_version in prev_versions:
@@ -161,7 +161,7 @@ class UptakeMonitoring(BaseScript, VirtualenvMixin, BuildbotMixin):
         credentials_file = os.path.join(os.getcwd(),
                                         self.config["credentials_file"])
         credentials = {}
-        execfile(credentials_file, credentials)
+        exec(compile(open(credentials_file, "rb").read(), credentials_file, 'exec'), credentials)
         auth = (credentials['tuxedoUsername'], credentials['tuxedoPassword'])
         self.info("Starting the loop to determine the uptake monitoring ...")
 
diff --git a/testing/mozharness/scripts/spidermonkey_build.py b/testing/mozharness/scripts/spidermonkey_build.py
index 5522545da5..b474e1aec0 100755
--- a/testing/mozharness/scripts/spidermonkey_build.py
+++ b/testing/mozharness/scripts/spidermonkey_build.py
@@ -22,7 +22,7 @@ from mozharness.mozilla.purge import PurgeMixin
 from mozharness.mozilla.mock import MockMixin
 from mozharness.mozilla.tooltool import TooltoolMixin
 
-SUCCESS, WARNINGS, FAILURE, EXCEPTION, RETRY = xrange(5)
+SUCCESS, WARNINGS, FAILURE, EXCEPTION, RETRY = range(5)
 
 
 def requires(*queries):
diff --git a/testing/mozharness/test/test_base_config.py b/testing/mozharness/test/test_base_config.py
index 42ec7a641d..84784d7bca 100644
--- a/testing/mozharness/test/test_base_config.py
+++ b/testing/mozharness/test/test_base_config.py
@@ -32,7 +32,7 @@ class TestParseConfigFile(unittest.TestCase):
                            output='dict'):
         global_dict = {}
         local_dict = {}
-        execfile(filename, global_dict, local_dict)
+        exec(compile(open(filename, "rb").read(), filename, 'exec'), global_dict, local_dict)
         return local_dict['config']
 
     def test_json_config(self):
diff --git a/testing/mozharness/test/test_base_python.py b/testing/mozharness/test/test_base_python.py
index c013576f07..734dd6345a 100644
--- a/testing/mozharness/test/test_base_python.py
+++ b/testing/mozharness/test/test_base_python.py
@@ -9,7 +9,7 @@ here = os.path.dirname(os.path.abspath(__file__))
 class TestVirtualenvMixin(unittest.TestCase):
     def test_package_versions(self):
         example = os.path.join(here, 'pip-freeze.example.txt')
-        output = file(example).read()
+        output = open(example).read()
         mixin = python.VirtualenvMixin()
         packages = mixin.package_versions(output)
 
diff --git a/testing/mozharness/test/test_base_script.py b/testing/mozharness/test/test_base_script.py
index c069a82f38..47382a68a8 100644
--- a/testing/mozharness/test/test_base_script.py
+++ b/testing/mozharness/test/test_base_script.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
 import gc
 import mock
 import os
@@ -54,7 +55,7 @@ def get_debug_script_obj():
 
 def _post_fatal(self, **kwargs):
     fh = open('tmpfile_stdout', 'w')
-    print >>fh, test_string
+    print(test_string, file=fh)
     fh.close()
 
 
@@ -100,7 +101,7 @@ class TestScript(unittest.TestCase):
             # now let's see if only unique items were added from each config
             t_override = local_cfg_files.get('test/test_override.py', {})
             self.assertTrue(
-                t_override.get('keep_string') == "don't change me" and len(t_override.keys()) == 1,
+                t_override.get('keep_string') == "don't change me" and len(list(t_override.keys())) == 1,
                 msg="--dump-config-hierarchy dumped wrong keys/value for "
                     "`test/test_override.py`. There should only be one "
                     "item and it should be unique to all the other "
@@ -425,7 +426,7 @@ class TestHelperFunctions(unittest.TestCase):
         win32file.CreateDirectoryExW(u'.', path)
 
         for x in range(0, 20):
-            print("path=%s" % path)
+            print(("path=%s" % path))
             path = path + u'\\%sxxxxxxxxxxxxxxxxxxxx' % x
             win32file.CreateDirectoryExW(u'.', path)
         self.s.rmtree('test_dir')
@@ -445,7 +446,7 @@ class TestHelperFunctions(unittest.TestCase):
     def test_chmod(self):
         self._create_temp_file()
         self.s = script.BaseScript(initial_config_file='test/test.json')
-        self.s.chmod(self.temp_file, 0100700)
+        self.s.chmod(self.temp_file, 0o100700)
         self.assertEqual(os.stat(self.temp_file)[0], 33216,
                          msg="chmod unsuccessful")
 
@@ -694,7 +695,7 @@ class TestRetry(unittest.TestCase):
         args = (1, 'two', 3)
         kwargs = dict(foo='a', bar=7)
         ret = self.s.retry(self._mirrorArgs, args=args, kwargs=kwargs.copy(), sleeptime=0)
-        print ret
+        print(ret)
         self.assertEqual(ret[0], args)
         self.assertEqual(ret[1], kwargs)
 
diff --git a/testing/mozharness/test/test_l10n_locales.py b/testing/mozharness/test/test_l10n_locales.py
index e8372a9fbb..7889a7dbe3 100644
--- a/testing/mozharness/test/test_l10n_locales.py
+++ b/testing/mozharness/test/test_l10n_locales.py
@@ -85,21 +85,21 @@ class TestLocalesMixin(unittest.TestCase):
 
     def test_query_abs_dirs_base(self):
         l = self._get_query_abs_dirs_obj()
-        dirs = l.query_abs_dirs().keys()
+        dirs = list(l.query_abs_dirs().keys())
         dirs.sort()
         self.assertEqual(dirs, self.BASE_ABS_DIRS)
 
     def test_query_abs_dirs_base2(self):
         l = self._get_query_abs_dirs_obj()
-        l.query_abs_dirs().keys()
-        dirs = l.query_abs_dirs().keys()
+        list(l.query_abs_dirs().keys())
+        dirs = list(l.query_abs_dirs().keys())
         dirs.sort()
         self.assertEqual(dirs, self.BASE_ABS_DIRS)
 
     def test_query_abs_dirs_l10n(self):
         l = self._get_query_abs_dirs_obj()
         l.config['l10n_dir'] = "l10n_dir"
-        dirs = l.query_abs_dirs().keys()
+        dirs = list(l.query_abs_dirs().keys())
         dirs.sort()
         expected_dirs = self.BASE_ABS_DIRS + ['abs_l10n_dir']
         expected_dirs.sort()
@@ -110,7 +110,7 @@ class TestLocalesMixin(unittest.TestCase):
         l.config['l10n_dir'] = "l10n_dir"
         l.config['mozilla_dir'] = "mozilla_dir"
         l.config['locales_dir'] = "locales_dir"
-        dirs = l.query_abs_dirs().keys()
+        dirs = list(l.query_abs_dirs().keys())
         dirs.sort()
         expected_dirs = self.BASE_ABS_DIRS + ['abs_mozilla_dir', 'abs_locales_src_dir', 'abs_l10n_dir']
         expected_dirs.sort()
@@ -122,7 +122,7 @@ class TestLocalesMixin(unittest.TestCase):
         l.config['mozilla_dir'] = "mozilla_dir"
         l.config['locales_dir'] = "locales_dir"
         l.config['objdir'] = "objdir"
-        dirs = l.query_abs_dirs().keys()
+        dirs = list(l.query_abs_dirs().keys())
         dirs.sort()
         expected_dirs = self.BASE_ABS_DIRS + ['abs_mozilla_dir', 'abs_locales_src_dir', 'abs_l10n_dir', 'abs_objdir', 'abs_merge_dir', 'abs_locales_dir']
         expected_dirs.sort()
diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
index 197cae8b44..8e4a648cb4 100644
--- a/testing/remotecppunittests.py
+++ b/testing/remotecppunittests.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import os, sys
 import subprocess
 import tempfile
@@ -58,7 +59,7 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
 
                 for info in apk_contents.infolist():
                     if info.filename.endswith(".so"):
-                        print >> sys.stderr, "Pushing %s.." % info.filename
+                        print("Pushing %s.." % info.filename, file=sys.stderr)
                         remote_file = posixpath.join(self.remote_bin_dir, os.path.basename(info.filename))
                         apk_contents.extract(info, tmpdir)
                         local_file = os.path.join(tmpdir, info.filename)
@@ -74,7 +75,7 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
         elif self.options.local_lib:
             for file in os.listdir(self.options.local_lib):
                 if file.endswith(".so"):
-                    print >> sys.stderr, "Pushing %s.." % file
+                    print("Pushing %s.." % file, file=sys.stderr)
                     remote_file = posixpath.join(self.remote_bin_dir, file)
                     local_file = os.path.join(self.options.local_lib, file)
                     self.device.pushFile(local_file, remote_file)
@@ -85,7 +86,7 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
                     for root, dirs, files in os.walk(local_arm_lib):
                         for file in files:
                             if (file.endswith(".so")):
-                                print >> sys.stderr, "Pushing %s.." % file
+                                print("Pushing %s.." % file, file=sys.stderr)
                                 remote_file = posixpath.join(self.remote_bin_dir, file)
                                 local_file = os.path.join(root, file)
                                 self.device.pushFile(local_file, remote_file)
@@ -236,7 +237,7 @@ def run_test_harness(options, args):
     else:
         dm = devicemanagerSUT.DeviceManagerSUT(options.device_ip, options.device_port, deviceRoot=options.remote_test_root)
         if not options.device_ip:
-            print "Error: you must provide a device IP to connect to via the --deviceIP option"
+            print("Error: you must provide a device IP to connect to via the --deviceIP option")
             sys.exit(1)
 
     options.xre_path = os.path.abspath(options.xre_path)
@@ -258,23 +259,23 @@ def main():
     mozlog.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not args:
-        print >>sys.stderr, """Usage: %s <test binary> [<test binary>...]""" % sys.argv[0]
+        print("""Usage: %s <test binary> [<test binary>...]""" % sys.argv[0], file=sys.stderr)
         sys.exit(1)
     if options.local_lib is not None and not os.path.isdir(options.local_lib):
-        print >>sys.stderr, """Error: --localLib directory %s not found""" % options.local_lib
+        print("""Error: --localLib directory %s not found""" % options.local_lib, file=sys.stderr)
         sys.exit(1)
     if options.local_apk is not None and not os.path.isfile(options.local_apk):
-        print >>sys.stderr, """Error: --apk file %s not found""" % options.local_apk
+        print("""Error: --apk file %s not found""" % options.local_apk, file=sys.stderr)
         sys.exit(1)
     if not options.xre_path:
-        print >>sys.stderr, """Error: --xre-path is required"""
+        print("""Error: --xre-path is required""", file=sys.stderr)
         sys.exit(1)
 
     log = mozlog.commandline.setup_logging("remotecppunittests", options,
                                            {"tbpl": sys.stdout})
     try:
         result = run_test_harness(options, args)
-    except Exception, e:
+    except Exception as e:
         log.error(str(e))
         result = False
     sys.exit(0 if result else 1)
diff --git a/testing/runcppunittests.py b/testing/runcppunittests.py
index fdd6abc1f6..24612024e0 100755
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -5,6 +5,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from __future__ import with_statement
+from __future__ import print_function
 import sys, os, tempfile, shutil
 from optparse import OptionParser
 import manifestparser
@@ -248,13 +249,13 @@ def main():
     mozlog.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not args:
-        print >>sys.stderr, """Usage: %s <test binary> [<test binary>...]""" % sys.argv[0]
+        print("""Usage: %s <test binary> [<test binary>...]""" % sys.argv[0], file=sys.stderr)
         sys.exit(1)
     if not options.xre_path:
-        print >>sys.stderr, """Error: --xre-path is required"""
+        print("""Error: --xre-path is required""", file=sys.stderr)
         sys.exit(1)
     if options.manifest_path and len(args) > 1:
-        print >>sys.stderr, "Error: multiple arguments not supported with --test-manifest"
+        print("Error: multiple arguments not supported with --test-manifest", file=sys.stderr)
         sys.exit(1)
     log = mozlog.commandline.setup_logging("cppunittests", options,
                                            {"tbpl": sys.stdout})
diff --git a/testing/runtimes/writeruntimes.py b/testing/runtimes/writeruntimes.py
index d67d5b0055..a3edfdd916 100644
--- a/testing/runtimes/writeruntimes.py
+++ b/testing/runtimes/writeruntimes.py
@@ -55,7 +55,7 @@ def write_runtimes(data, suite, indir=here, outdir=here):
 
     # identify a threshold of durations, below which we ignore
     runtimes = []
-    for result in data.itervalues():
+    for result in data.values():
         duration = int(result * 1000) if result else 0
         if duration:
             runtimes.append(duration)
@@ -66,7 +66,7 @@ def write_runtimes(data, suite, indir=here, outdir=here):
     omitted = []
     specified = indata if indata else {}
     current_tests = []
-    for test, duration in data.iteritems():
+    for test, duration in data.items():
         current_tests.append(test)
         duration = int(duration * 1000) if duration else 0
         if duration > 0 and duration < threshold:
diff --git a/testing/talos/INSTALL.py b/testing/talos/INSTALL.py
index debc843f04..32e6c6a1e0 100755
--- a/testing/talos/INSTALL.py
+++ b/testing/talos/INSTALL.py
@@ -10,7 +10,7 @@ installation script for talos. This script:
 import os
 import subprocess
 import sys
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 try:
     from subprocess import check_call as call
 except:
@@ -47,7 +47,7 @@ def main(args=sys.argv[1:]):
                                     '--system-site-packages',
                                     here],
                                    stdin=subprocess.PIPE)
-        stdout, stderr = process.communicate(input=urllib2.urlopen(VIRTUALENV).read())
+        stdout, stderr = process.communicate(input=six.moves.urllib.request.urlopen(VIRTUALENV).read())
 
     # find the virtualenv's python
     for i in ('bin', 'Scripts'):
diff --git a/testing/talos/talos/cmanager_linux.py b/testing/talos/talos/cmanager_linux.py
index 54de636ddc..12419c9730 100644
--- a/testing/talos/talos/cmanager_linux.py
+++ b/testing/talos/talos/cmanager_linux.py
@@ -2,9 +2,10 @@
 # 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 print_function
 import re
 import subprocess
-from cmanager import CounterManager
+from .cmanager import CounterManager
 
 
 def xrestop(binary='xrestop'):
diff --git a/testing/talos/talos/cmanager_mac.py b/testing/talos/talos/cmanager_mac.py
index fe57778a31..9d1d01b653 100644
--- a/testing/talos/talos/cmanager_mac.py
+++ b/testing/talos/talos/cmanager_mac.py
@@ -4,8 +4,9 @@
 
 """CounterManager for Mac OSX"""
 
+from __future__ import print_function
 import subprocess
-from cmanager import CounterManager
+from .cmanager import CounterManager
 import sys
 
 
@@ -20,7 +21,7 @@ def GetProcessData(pid):
         handle.wait()
         data = handle.stdout.readlines()
     except:
-        print("Unexpected error executing '%s': %s", (command, sys.exc_info()))
+        print(("Unexpected error executing '%s': %s", (command, sys.exc_info())))
         raise
 
     # First line is header output should look like:
@@ -75,12 +76,12 @@ class MacCounterManager(CounterManager):
     def getCounterValue(self, counterName):
         """Returns the last value of the counter 'counterName'"""
         if counterName not in self.registeredCounters:
-            print("Warning: attempting to collect counter %s and it is not"
-                  " registered" % counterName)
+            print(("Warning: attempting to collect counter %s and it is not"
+                  " registered" % counterName))
             return
 
         try:
             return self.registeredCounters[counterName][0](self.pid)
         except Exception as e:
-            print("Error in collecting counter: %s, pid: %s, exception: %s"
-                  % (counterName, self.pid, e))
+            print(("Error in collecting counter: %s, pid: %s, exception: %s"
+                  % (counterName, self.pid, e)))
diff --git a/testing/talos/talos/cmanager_win32.py b/testing/talos/talos/cmanager_win32.py
index cfd215496e..54a9dd135a 100644
--- a/testing/talos/talos/cmanager_win32.py
+++ b/testing/talos/talos/cmanager_win32.py
@@ -2,14 +2,14 @@
 # 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 cmanager import CounterManager
+from .cmanager import CounterManager
 from ctypes import windll
 from ctypes.wintypes import DWORD, HANDLE, LPSTR, LPCSTR, LPCWSTR, Structure, \
     pointer, LONG
 from ctypes import byref, create_string_buffer, memmove, Union, c_double, \
     c_longlong
 import struct
-from utils import TalosError
+from .utils import TalosError
 pdh = windll.pdh
 
 _LONGLONG = c_longlong
diff --git a/testing/talos/talos/cmdline.py b/testing/talos/talos/cmdline.py
index 7d4cd20d9e..864b77d500 100644
--- a/testing/talos/talos/cmdline.py
+++ b/testing/talos/talos/cmdline.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import argparse
 import os
 
@@ -26,14 +27,14 @@ class _ListTests(_StopAction):
         print('================\n')
         test_class_names = [
             (test_class.name(), test_class.description())
-            for test_class in test.test_dict().itervalues()
+            for test_class in test.test_dict(.values())
         ]
         test_class_names.sort()
         for name, description in test_class_names:
             print(name)
-            print('-'*len(name))
+            print(('-'*len(name)))
             print(description)
-            print  # Appends a single blank line to the end
+            print()  # Appends a single blank line to the end
         parser.exit()
 
 
@@ -45,8 +46,8 @@ class _ListSuite(_StopAction):
         max_suite_name = max([len(s) for s in conf])
         pattern = " %%-%ds (%%s)" % max_suite_name
         for name in conf:
-            print(pattern % (name, ':'.join(conf[name]['tests'])))
-        print
+            print((pattern % (name, ':'.join(conf[name]['tests']))))
+        print()
         parser.exit()
 
 
diff --git a/testing/talos/talos/config.py b/testing/talos/talos/config.py
index 4f7b23ab6a..bdc0683684 100644
--- a/testing/talos/talos/config.py
+++ b/testing/talos/talos/config.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import sys
 import os
 import copy
@@ -377,7 +378,7 @@ def get_test(config, global_overrides, counters, test_instance):
             _counters = getattr(test_instance, key)
             _counters.extend([counter for counter in counters
                               if counter not in _counters])
-    return dict(test_instance.items())
+    return dict(list(test_instance.items()))
 
 
 @validator
@@ -462,6 +463,6 @@ def get_configs(argv=None):
 
 if __name__ == '__main__':
     cfgs = get_configs()
-    print(cfgs[0])
-    print
-    print(cfgs[1])
+    print((cfgs[0]))
+    print()
+    print((cfgs[1]))
diff --git a/testing/talos/talos/ffsetup.py b/testing/talos/talos/ffsetup.py
index 14ff576d54..09291634a6 100644
--- a/testing/talos/talos/ffsetup.py
+++ b/testing/talos/talos/ffsetup.py
@@ -61,7 +61,7 @@ class FFSetup(object):
 
     def _init_env(self):
         self.env = dict(os.environ)
-        for k, v in self.browser_config['env'].iteritems():
+        for k, v in self.browser_config['env'].items():
             self.env[k] = str(v)
         self.env['MOZ_CRASHREPORTER_NO_REPORT'] = '1'
         # for winxp e10s logging:
diff --git a/testing/talos/talos/mainthreadio.py b/testing/talos/talos/mainthreadio.py
index 112aaace36..52d80cdd6b 100644
--- a/testing/talos/talos/mainthreadio.py
+++ b/testing/talos/talos/mainthreadio.py
@@ -3,9 +3,10 @@
 # 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 print_function
 import os
-import utils
-import whitelist
+from . import utils
+from . import whitelist
 
 SCRIPT_DIR = os.path.abspath(os.path.realpath(os.path.dirname(__file__)))
 
@@ -86,7 +87,7 @@ def parse(logfilename, data):
                     stage = stage + 1
             return True
     except IOError as e:
-        print("%s: %s" % (e.filename, e.strerror))
+        print(("%s: %s" % (e.filename, e.strerror)))
         return False
 
 
@@ -95,7 +96,7 @@ def write_output(outfilename, data):
     try:
         with open(outfilename, 'w') as outfile:
             outfile.write("[\n")
-            for idx, (key, value) in utils.indexed_items(data.iteritems()):
+            for idx, (key, value) in utils.indexed_items(data.items()):
                 output = "    [\"%s\", \"%s\", \"%s\", \"%s\", %d, %d, %f]" % (
                     key[0], key[1], key[2], key[3], value[KEY_COUNT],
                     value[KEY_RUN_COUNT], value[KEY_DURATION])
@@ -107,17 +108,17 @@ def write_output(outfilename, data):
             outfile.write("]\n")
             return True
     except IOError as e:
-        print("%s: %s" % (e.filename, e.strerror))
+        print(("%s: %s" % (e.filename, e.strerror)))
         return False
 
 
 def main(argv):
     if len(argv) < 4:
-        print("Usage: %s <main_thread_io_log_file> <output_file> <xre_path>"
-              % argv[0])
+        print(("Usage: %s <main_thread_io_log_file> <output_file> <xre_path>"
+              % argv[0]))
         return 1
     if not os.path.exists(argv[3]):
-        print("XRE Path \"%s\" does not exist" % argv[3])
+        print(("XRE Path \"%s\" does not exist" % argv[3]))
         return 1
     data = {}
     if not parse(argv[1], data):
diff --git a/testing/talos/talos/output.py b/testing/talos/talos/output.py
index 003e98f021..84faf5432a 100755
--- a/testing/talos/talos/output.py
+++ b/testing/talos/talos/output.py
@@ -5,14 +5,14 @@
 
 """output formats for Talos"""
 
-import filter
+from . import filter
 import json
-import utils
+from . import utils
 
 from mozlog import get_proxy_logger
 
 # NOTE: we have a circular dependency with output.py when we import results
-import results as TalosResults
+from . import results as TalosResults
 
 LOG = get_proxy_logger()
 
diff --git a/testing/talos/talos/profiler/symFileManager.py b/testing/talos/talos/profiler/symFileManager.py
index 0413a9ee81..108385e5a2 100755
--- a/testing/talos/talos/profiler/symFileManager.py
+++ b/testing/talos/talos/profiler/symFileManager.py
@@ -2,7 +2,7 @@
 # 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 symLogging import LogTrace, LogError, LogMessage
+from .symLogging import LogTrace, LogError, LogMessage
 
 import itertools
 import os
@@ -165,7 +165,7 @@ class SymFileManager:
             return None
 
         logString = "Found " + \
-            str(len(symbolMap.keys())) + " unique entries from "
+            str(len(list(symbolMap.keys()))) + " unique entries from "
         logString += str(publicCount) + " PUBLIC lines, " + \
             str(funcCount) + " FUNC lines"
         LogTrace(logString)
diff --git a/testing/talos/talos/profiler/symLogging.py b/testing/talos/talos/profiler/symLogging.py
index 2a6aa89936..b50cce6b24 100755
--- a/testing/talos/talos/profiler/symLogging.py
+++ b/testing/talos/talos/profiler/symLogging.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import sys
 import threading
 import time
@@ -13,17 +14,17 @@ def LogTrace(string):
     global gEnableTracing
     if gEnableTracing:
         threadName = threading.currentThread().getName().ljust(12)
-        print >> sys.stdout, time.asctime() + " " + threadName + " TRACE " + \
-            string
+        print(time.asctime() + " " + threadName + " TRACE " + \
+            string, file=sys.stdout)
 
 
 def LogError(string):
     threadName = threading.currentThread().getName().ljust(12)
-    print >> sys.stderr, time.asctime() + " " + threadName + " ERROR " + \
-        string
+    print(time.asctime() + " " + threadName + " ERROR " + \
+        string, file=sys.stderr)
 
 
 def LogMessage(string):
     threadName = threading.currentThread().getName().ljust(12)
-    print >> sys.stdout, time.asctime() + " " + threadName + "       " + \
-        string
+    print(time.asctime() + " " + threadName + "       " + \
+        string, file=sys.stdout)
diff --git a/testing/talos/talos/profiler/symbolication.py b/testing/talos/talos/profiler/symbolication.py
index 4bb07dfe83..51f8f4a62e 100755
--- a/testing/talos/talos/profiler/symbolication.py
+++ b/testing/talos/talos/profiler/symbolication.py
@@ -9,12 +9,13 @@ import os
 import platform
 import re
 import subprocess
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import zipfile
 from distutils import spawn
-from symFileManager import SymFileManager
-from symbolicationRequest import SymbolicationRequest
-from symLogging import LogMessage
+from .symFileManager import SymFileManager
+from .symbolicationRequest import SymbolicationRequest
+from .symLogging import LogMessage
+import six
 
 """
 Symbolication is broken when using type 'str' in python 2.7, so we use 'basestring'.
@@ -22,9 +23,9 @@ But for python 3.0 compatibility, 'basestring' isn't defined, but the 'str' type
 So we force 'basestring' to 'str'.
 """
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 
 class SymbolError(Exception):
@@ -145,7 +146,7 @@ class ProfileSymbolicator:
         LogMessage("Retrieving symbol zip from {symbol_zip_url}...".format(
             symbol_zip_url=symbol_zip_url))
         try:
-            io = urllib2.urlopen(symbol_zip_url, None, 30)
+            io = six.moves.urllib.request.urlopen(symbol_zip_url, None, 30)
             with zipfile.ZipFile(cStringIO.StringIO(io.read())) as zf:
                 self.integrate_symbol_zip(zf)
             self._create_file_if_not_exists(self._marker_file(symbol_zip_url))
@@ -276,7 +277,7 @@ class ProfileSymbolicator:
             delta_time = profile_start_time - self.main_start_time
 
         for i, thread in enumerate(profile_json["threads"]):
-            if isinstance(thread, basestring):
+            if isinstance(thread, str):
                 thread_json = json.loads(thread)
                 self.symbolicate_profile(thread_json)
                 profile_json["threads"][i] = json.dumps(thread_json)
@@ -307,7 +308,7 @@ class ProfileSymbolicator:
     def _find_addresses_v3(self, profile_json):
         addresses = set()
         for thread in profile_json["threads"]:
-            if isinstance(thread, basestring):
+            if isinstance(thread, str):
                 continue
             for s in thread["stringTable"]:
                 if s[0:2] == "0x":
@@ -316,7 +317,7 @@ class ProfileSymbolicator:
 
     def _substitute_symbols_v3(self, profile_json, symbolication_table):
         for thread in profile_json["threads"]:
-            if isinstance(thread, basestring):
+            if isinstance(thread, str):
                 continue
             for i, s in enumerate(thread["stringTable"]):
                 thread["stringTable"][i] = symbolication_table.get(s, s)
@@ -356,7 +357,7 @@ class ProfileSymbolicator:
                 libs_with_symbols[lib["start"]] = {
                     "library": lib, "symbols": set()}
             libs_with_symbols[lib["start"]]["symbols"].add(address)
-        return libs_with_symbols.values()
+        return list(libs_with_symbols.values())
 
     def _module_from_lib(self, lib):
         if "breakpadId" in lib:
diff --git a/testing/talos/talos/profiler/symbolicationRequest.py b/testing/talos/talos/profiler/symbolicationRequest.py
index 9b5fb0ab2c..f986356c64 100755
--- a/testing/talos/talos/profiler/symbolicationRequest.py
+++ b/testing/talos/talos/profiler/symbolicationRequest.py
@@ -2,11 +2,12 @@
 # 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 symLogging import LogTrace, LogError
+from .symLogging import LogTrace, LogError
 
 import re
 import json
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six
 
 # Precompiled regex for validating lib names
 # Empty lib name means client couldn't associate frame with any lib
@@ -22,9 +23,9 @@ But for python 3.0 compatibility, 'basestring' isn't defined, but the 'str' type
 So we force 'basestring' to 'str'.
 """
 try:
-    basestring
+    str
 except NameError:
-    basestring = str
+    str = str
 
 
 class ModuleV3:
@@ -35,11 +36,11 @@ class ModuleV3:
 
 
 def getModuleV3(libName, breakpadId):
-    if not isinstance(libName, basestring) or not gLibNameRE.match(libName):
+    if not isinstance(libName, str) or not gLibNameRE.match(libName):
         LogTrace("Bad library name: " + str(libName))
         return None
 
-    if not isinstance(breakpadId, basestring):
+    if not isinstance(breakpadId, str):
         LogTrace("Bad breakpad id: " + str(breakpadId))
         return None
 
@@ -202,9 +203,9 @@ class SymbolicationRequest:
                 }
                 requestJson = json.dumps(requestObj)
                 headers = {"Content-Type": "application/json"}
-                requestHandle = urllib2.Request(url, requestJson, headers)
+                requestHandle = six.moves.urllib.request.Request(url, requestJson, headers)
                 try:
-                    response = urllib2.urlopen(requestHandle)
+                    response = six.moves.urllib.request.urlopen(requestHandle)
                 except Exception as e:
                     if requestVersion == 4:
                         # Try again with version 3
diff --git a/testing/talos/talos/results.py b/testing/talos/talos/results.py
index de81ac4902..dabe2d6e17 100755
--- a/testing/talos/talos/results.py
+++ b/testing/talos/talos/results.py
@@ -9,6 +9,7 @@ objects and methods for parsing and serializing Talos results
 see https://wiki.mozilla.org/Buildbot/Talos/DataFormat
 """
 
+from __future__ import print_function
 import json
 import os
 import re
@@ -55,11 +56,11 @@ class TalosResults(object):
                 )
             except:
                 pass
-            print('\nFAIL: %s' % str(e).replace('\n', '\nRETURN:'))
+            print(('\nFAIL: %s' % str(e).replace('\n', '\nRETURN:')))
             raise e
 
         if tbpl_output:
-            print("TinderboxPrint: TalosResult: %s" % json.dumps(tbpl_output))
+            print(("TinderboxPrint: TalosResult: %s" % json.dumps(tbpl_output)))
 
 
 class TestResults(object):
@@ -420,14 +421,14 @@ class BrowserLogResults(object):
         self.mainthread_io(counter_results)
 
         if not set(counters).union(set(mainthread_counters))\
-                .intersection(counter_results.keys()):
+                .intersection(list(counter_results.keys())):
             # no xperf counters to accumulate
             return
 
         filename = 'etl_output_thread_stats.csv'
         if not os.path.exists(filename):
-            print("Warning: we are looking for xperf results file %s, and"
-                  " didn't find it" % filename)
+            print(("Warning: we are looking for xperf results file %s, and"
+                  " didn't find it" % filename))
             return
 
         contents = open(filename).read()
@@ -455,11 +456,11 @@ class BrowserLogResults(object):
                 counter_results.setdefault(counter_name, []).append(value)
                 self.using_xperf = True
 
-        if (set(mainthread_counters).intersection(counter_results.keys())):
+        if (set(mainthread_counters).intersection(list(counter_results.keys()))):
             filename = 'etl_output.csv'
             if not os.path.exists(filename):
-                print("Warning: we are looking for xperf results file"
-                      " %s, and didn't find it" % filename)
+                print(("Warning: we are looking for xperf results file"
+                      " %s, and didn't find it" % filename))
                 return
 
             contents = open(filename).read()
@@ -485,7 +486,7 @@ class BrowserLogResults(object):
 
         counters = ['Main', 'Content']
         if not set(['%s_RSS' % i for i in counters])\
-                .intersection(counter_results.keys()):
+                .intersection(list(counter_results.keys())):
             # no RSS counters to accumulate
             return
         for line in self.results_raw.split('\n'):
diff --git a/testing/talos/talos/run_tests.py b/testing/talos/talos/run_tests.py
index 1e5c3ac508..6161d2a35a 100755
--- a/testing/talos/talos/run_tests.py
+++ b/testing/talos/talos/run_tests.py
@@ -4,13 +4,14 @@
 # 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 print_function
 import mozversion
 import os
 import sys
 import time
 import traceback
-import urllib
-import utils
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
+from . import utils
 import mozhttpd
 
 from mozlog import get_proxy_logger
@@ -40,9 +41,9 @@ def buildCommandLine(test):
 
     # sanity check pageloader values
     # mandatory options: tpmanifest, tpcycles
-    if test['tpcycles'] not in range(1, 1000):
+    if test['tpcycles'] not in list(range(1, 1000)):
         raise TalosError('pageloader cycles must be int 1 to 1,000')
-    if test.get('tpdelay') and test['tpdelay'] not in range(1, 10000):
+    if test.get('tpdelay') and test['tpdelay'] not in list(range(1, 10000)):
         raise TalosError('pageloader delay must be int 1 to 10,000')
     if 'tpmanifest' not in test:
         raise TalosError("tpmanifest not found in test: %s" % test)
@@ -101,7 +102,7 @@ def run_tests(config, browser_config):
                 test[path] = utils.interpolate(test[path])
         if test.get('tpmanifest'):
             test['tpmanifest'] = \
-                os.path.normpath('file:/%s' % (urllib.quote(test['tpmanifest'],
+                os.path.normpath('file:/%s' % (six.moves.urllib.parse.quote(test['tpmanifest'],
                                                '/\\t:\\')))
         if not test.get('url'):
             # build 'url' for tptest
@@ -150,7 +151,7 @@ def run_tests(config, browser_config):
         browser_config['sourcestamp'] = version_info['application_changeset']
     except KeyError:
         if not browser_config['develop']:
-            print("unable to find changeset or repository: %s" % version_info)
+            print(("unable to find changeset or repository: %s" % version_info))
             sys.exit()
         else:
             browser_config['repository'] = 'develop'
@@ -228,8 +229,8 @@ def run_tests(config, browser_config):
     if results_urls:
         talos_results.output(results_urls)
         if browser_config['develop'] or config['sps_profile']:
-            print("Thanks for running Talos locally. Results are in %s"
-                  % (results_urls['output_urls']))
+            print(("Thanks for running Talos locally. Results are in %s"
+                  % (results_urls['output_urls'])))
 
     # we will stop running tests on a failed test, or we will return 0 for
     # green
diff --git a/testing/talos/talos/scripts/report.py b/testing/talos/talos/scripts/report.py
index 7aebc51c60..9bd23a1f6f 100644
--- a/testing/talos/talos/scripts/report.py
+++ b/testing/talos/talos/scripts/report.py
@@ -123,11 +123,11 @@ def main():
     tuple_list = get_all_test_tuples()
     f = 'report'
     if args.platform:
-        tuple_list = filter(lambda x: x[4] == args.platform, tuple_list)
+        tuple_list = [x for x in tuple_list if x[4] == args.platform]
         f += '-%s' % args.platform
 
     if args.test:
-        tuple_list = filter(lambda x: x[3] == args.test, tuple_list)
+        tuple_list = [x for x in tuple_list if x[3] == args.test]
         f += '-%s' % args.test
 
     f += '-%s' % args.mode
diff --git a/testing/talos/talos/talos_process.py b/testing/talos/talos/talos_process.py
index b601240f33..2a553f43d4 100644
--- a/testing/talos/talos/talos_process.py
+++ b/testing/talos/talos/talos_process.py
@@ -10,7 +10,7 @@ from threading import Event
 
 from mozlog import get_proxy_logger
 
-from utils import TalosError
+from .utils import TalosError
 
 LOG = get_proxy_logger()
 
diff --git a/testing/talos/talos/talosconfig.py b/testing/talos/talos/talosconfig.py
index 2645a56bf3..328399cedd 100644
--- a/testing/talos/talos/talosconfig.py
+++ b/testing/talos/talos/talosconfig.py
@@ -1,9 +1,10 @@
+from __future__ import print_function
 import os
 import json
 
 
 def writeConfigFile(obj, vals):
-    data = dict((opt, obj[opt]) for opt in (vals or obj.keys()))
+    data = dict((opt, obj[opt]) for opt in (vals or list(obj.keys())))
     return json.dumps(data)
 
 
diff --git a/testing/talos/talos/test.py b/testing/talos/talos/test.py
index 6df5835bb7..53c8995cd6 100644
--- a/testing/talos/talos/test.py
+++ b/testing/talos/talos/test.py
@@ -65,7 +65,7 @@ class Test(object):
 
     def __str__(self):
         """string form appropriate for YAML output"""
-        items = self.items()
+        items = list(self.items())
 
         key, value = items.pop(0)
         lines = ["- %s: %s" % (key, value)]
diff --git a/testing/talos/talos/ttest.py b/testing/talos/talos/ttest.py
index 3c57f020dd..89a4cc1f54 100644
--- a/testing/talos/talos/ttest.py
+++ b/testing/talos/talos/ttest.py
@@ -12,14 +12,15 @@
      - waits for a 'dump' from the browser
 """
 
+from __future__ import print_function
 import os
 import sys
 import platform
-import results
+from . import results
 import subprocess
-import utils
+from . import utils
 import mozcrash
-import talosconfig
+from . import talosconfig
 import shutil
 import mozfile
 
diff --git a/testing/talos/talos/utils.py b/testing/talos/talos/utils.py
index 2b332d2301..8473cef828 100755
--- a/testing/talos/talos/utils.py
+++ b/testing/talos/talos/utils.py
@@ -6,9 +6,9 @@
 
 import os
 import time
-import urlparse
+import six.moves.urllib.parse
 import string
-import urllib
+import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
 import json
 import re
 import platform
@@ -136,7 +136,7 @@ def urlsplit(url, default_scheme='file'):
         return ['file', '', url[len('file://'):], '', '']
 
     # split the URL and return a list
-    return [i for i in urlparse.urlsplit(url)]
+    return [i for i in six.moves.urllib.parse.urlsplit(url)]
 
 
 def parse_pref(value):
@@ -170,9 +170,9 @@ def GenerateBrowserCommandLine(browser_path, extra_args, profile_dir,
             command_args.extend(['-tpprofilinginfo',
                                  json.dumps(profiling_info)])
         elif url.find('?') != -1:
-            url += '&' + urllib.urlencode(profiling_info)
+            url += '&' + six.moves.urllib.parse.urlencode(profiling_info)
         else:
-            url += '?' + urllib.urlencode(profiling_info)
+            url += '?' + six.moves.urllib.parse.urlencode(profiling_info)
 
     command_args.extend(url.split(' '))
 
@@ -184,7 +184,7 @@ def indexed_items(itr):
     Generator that allows us to figure out which item is the last one so
     that we can serialize this data properly
     """
-    prev_i, prev_val = 0, itr.next()
+    prev_i, prev_val = 0, next(itr)
     for i, val in enumerate(itr, start=1):
         yield prev_i, prev_val
         prev_i, prev_val = i, val
diff --git a/testing/talos/talos/whitelist.py b/testing/talos/talos/whitelist.py
index 1e4c4117eb..7d07095152 100644
--- a/testing/talos/talos/whitelist.py
+++ b/testing/talos/talos/whitelist.py
@@ -3,9 +3,10 @@
 # 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 print_function
 import json
 import os
-import utils
+from . import utils
 
 KEY_XRE = '{xre}'
 DEFAULT_DURATION = 100.0
@@ -37,7 +38,7 @@ class Whitelist:
                 self.listmap[whitelist_name.lower()] = temp[whitelist_name]
 
         except IOError as e:
-            print("%s: %s" % (e.filename, e.strerror))
+            print(("%s: %s" % (e.filename, e.strerror)))
             return False
         return True
 
@@ -45,7 +46,7 @@ class Whitelist:
         filename = filename.lower()
         filename.replace(' (x86)', '')
 
-        for path, subst in self.path_substitutions.iteritems():
+        for path, subst in self.path_substitutions.items():
             parts = filename.split(path)
             if len(parts) >= 2:
                 if self.PRE_PROFILE == '' and subst == '{profile}':
@@ -68,7 +69,7 @@ class Whitelist:
 
                 filename = "%s%s" % (subst, path.join(parts[1:]))
 
-        for old_name, new_name in self.name_substitutions.iteritems():
+        for old_name, new_name in self.name_substitutions.items():
             parts = filename.split(old_name)
             if len(parts) >= 2:
                 filename = "%s%s" % (parts[0], new_name)
@@ -77,7 +78,7 @@ class Whitelist:
 
     def check(self, test, file_name_index):
         errors = {}
-        for row_key in test.iterkeys():
+        for row_key in test.keys():
             filename = self.sanitize_filename(row_key[file_name_index])
 
             if filename in self.listmap:
@@ -94,7 +95,7 @@ class Whitelist:
 
     def checkDuration(self, test, file_name_index, file_duration_index):
         errors = {}
-        for idx, (row_key, row_value) in utils.indexed_items(test.iteritems()):
+        for idx, (row_key, row_value) in utils.indexed_items(test.items()):
             if row_value[file_duration_index] > DEFAULT_DURATION:
                 filename = self.sanitize_filename(row_key[file_name_index])
                 if filename in self.listmap and \
@@ -127,7 +128,7 @@ class Whitelist:
     @staticmethod
     def get_error_strings(errors):
         error_strs = []
-        for filename, data in errors.iteritems():
+        for filename, data in errors.items():
             for datum in data:
                 error_strs.append("File '%s' was accessed and we were not"
                                   " expecting it: %r" % (filename, datum))
@@ -135,8 +136,8 @@ class Whitelist:
 
     def print_errors(self, error_strs):
         for error_msg in error_strs:
-            print("TEST-UNEXPECTED-FAIL | %s | %s" % (self.test_name,
-                                                      error_msg))
+            print(("TEST-UNEXPECTED-FAIL | %s | %s" % (self.test_name,
+                                                      error_msg)))
 
     # Note that we don't store dependent libs in listmap. This makes
     # save_baseline cleaner. Since a baseline whitelist should not include
@@ -153,5 +154,5 @@ class Whitelist:
                     {'ignore': True} for lib in libs}
             return True
         except IOError as e:
-            print("%s: %s" % (e.filename, e.strerror))
+            print(("%s: %s" % (e.filename, e.strerror)))
             return False
diff --git a/testing/talos/talos/xtalos/__init__.py b/testing/talos/talos/xtalos/__init__.py
index 73122f3553..ec0dcb9fca 100644
--- a/testing/talos/talos/xtalos/__init__.py
+++ b/testing/talos/talos/xtalos/__init__.py
@@ -1,5 +1,5 @@
 # xtalos: talos + xperf
 
-from start_xperf import start  # noqa
-from start_xperf import start_from_config  # noqa
-import etlparser  # noqa
+from .start_xperf import start  # noqa
+from .start_xperf import start_from_config  # noqa
+from . import etlparser  # noqa
diff --git a/testing/talos/talos/xtalos/etlparser.py b/testing/talos/talos/xtalos/etlparser.py
index d52c112e18..e9a3c42156 100644
--- a/testing/talos/talos/xtalos/etlparser.py
+++ b/testing/talos/talos/xtalos/etlparser.py
@@ -4,11 +4,12 @@
 # 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 print_function
 import csv
 import re
 import os
 import sys
-import xtalos
+from . import xtalos
 import subprocess
 import json
 import mozfile
@@ -79,7 +80,7 @@ def getIndex(eventType, colName):
 
 
 def readFile(filename):
-    print("etlparser: in readfile: %s" % filename)
+    print(("etlparser: in readfile: %s" % filename))
     data = csv.reader(open(filename, 'rb'), delimiter=',', quotechar='"',
                       skipinitialspace=True)
     data = filterOutHeader(data)
@@ -150,7 +151,7 @@ def etl2csv(xperf_path, etl_filename, debug=False):
                  '%s.kernel' % etl_filename,
                  etl_filename]
     if debug:
-        print("executing '%s'" % subprocess.list2cmdline(xperf_cmd))
+        print(("executing '%s'" % subprocess.list2cmdline(xperf_cmd)))
     subprocess.call(xperf_cmd)
 
     csv_filename = '%s.csv' % etl_filename
@@ -158,7 +159,7 @@ def etl2csv(xperf_path, etl_filename, debug=False):
                  '-i', etl_filename,
                  '-o', csv_filename]
     if debug:
-        print("executing '%s'" % subprocess.list2cmdline(xperf_cmd))
+        print(("executing '%s'" % subprocess.list2cmdline(xperf_cmd)))
     subprocess.call(xperf_cmd)
     return csv_filename
 
@@ -226,7 +227,7 @@ def loadWhitelist(filename):
     if not filename:
         return
     if not os.path.exists(filename):
-        print("Warning: xperf whitelist %s was not found" % filename)
+        print(("Warning: xperf whitelist %s was not found" % filename))
         return
     lines = open(filename).readlines()
     # Expand paths
@@ -276,7 +277,7 @@ def etlparser(xperf_path, etl_filename, processID, approot=None,
     io = {}
     stage = 0
 
-    print("reading etl filename: %s" % etl_filename)
+    print(("reading etl filename: %s" % etl_filename))
     csvname = etl2csv(xperf_path, etl_filename, debug=debug)
     for row in readFile(csvname):
         event = row[EVENTNAME_INDEX]
@@ -297,7 +298,7 @@ def etlparser(xperf_path, etl_filename, processID, approot=None,
         mozfile.remove(csvname)
 
     output = "thread, stage, counter, value\n"
-    for cntr in sorted(io.iterkeys()):
+    for cntr in sorted(io.keys()):
         output += "%s, %s\n" % (", ".join(cntr), str(io[cntr]))
     if outputFile:
         fname = "%s_thread_stats%s" % os.path.splitext(outputFile)
@@ -314,11 +315,10 @@ def etlparser(xperf_path, etl_filename, processID, approot=None,
 
     # Filter out stages, threads, and whitelisted files that we're not
     # interested in
-    filekeys = filter(lambda x: (all_stages or x[2] == stages[0]) and
+    filekeys = [x for x in files.keys() if (all_stages or x[2] == stages[0]) and
                                 (all_threads or x[1].endswith("(main)")) and
                                 (all_stages and x[2] != stages[0] or
-                                 not checkWhitelist(x[0], whitelist)),
-                      files.iterkeys())
+                                 not checkWhitelist(x[0], whitelist))]
 
     # output data
     for row in filekeys:
@@ -447,7 +447,7 @@ def etlparser(xperf_path, etl_filename, processID, approot=None,
         for error in errors:
             # NOTE: the ' :' is intentional, without the space before the :,
             # some parser will translate this
-            print("TEST-UNEXPECTED-FAIL : xperf: %s" % error)
+            print(("TEST-UNEXPECTED-FAIL : xperf: %s" % error))
 
         # We detect if browser_failures.txt exists to exit and turn the job
         # orange
diff --git a/testing/talos/talos/xtalos/parse_xperf.py b/testing/talos/talos/xtalos/parse_xperf.py
index c53425fa33..9dfde5d79d 100644
--- a/testing/talos/talos/xtalos/parse_xperf.py
+++ b/testing/talos/talos/xtalos/parse_xperf.py
@@ -4,17 +4,18 @@
 # 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 print_function
 import os
 import sys
-import xtalos
+from . import xtalos
 import subprocess
-import etlparser
+from . import etlparser
 
 
 def stop(xperf_path, debug=False):
     xperf_cmd = [xperf_path, '-stop', '-stop', 'talos_ses']
     if debug:
-        print("executing '%s'" % subprocess.list2cmdline(xperf_cmd))
+        print(("executing '%s'" % subprocess.list2cmdline(xperf_cmd)))
     subprocess.call(xperf_cmd)
 
 
diff --git a/testing/talos/talos/xtalos/start_xperf.py b/testing/talos/talos/xtalos/start_xperf.py
index 06585b4797..2e8503318f 100644
--- a/testing/talos/talos/xtalos/start_xperf.py
+++ b/testing/talos/talos/xtalos/start_xperf.py
@@ -4,9 +4,10 @@
 # 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 print_function
 import os
 import sys
-import xtalos
+from . import xtalos
 import subprocess
 
 
@@ -26,7 +27,7 @@ def start(xperf_path, xperf_providers, xperf_stackwalk, xperf_user_providers,
                  '-f', '%s.user' % etl_filename
                  ]
     if debug:
-        print("executing '%s'" % subprocess.list2cmdline(xperf_cmd))
+        print(("executing '%s'" % subprocess.list2cmdline(xperf_cmd)))
     subprocess.call(xperf_cmd)
 
 
diff --git a/testing/talos/talos/xtalos/xtalos.py b/testing/talos/talos/xtalos/xtalos.py
index df9a9eecc3..1e739ce1d7 100644
--- a/testing/talos/talos/xtalos/xtalos.py
+++ b/testing/talos/talos/xtalos/xtalos.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import argparse
 import json
@@ -120,7 +121,7 @@ class XtalosOptions(argparse.ArgumentParser):
         # ensure xperf path exists
         options.xperf_path = os.path.abspath(options.xperf_path)
         if not os.path.exists(options.xperf_path):
-            print("ERROR: xperf_path '%s' does not exist" % options.xperf_path)
+            print(("ERROR: xperf_path '%s' does not exist" % options.xperf_path))
             return None
 
         return options
diff --git a/testing/talos/talos_from_code.py b/testing/talos/talos_from_code.py
index 3ac2ffd582..fa93afa977 100644
--- a/testing/talos/talos_from_code.py
+++ b/testing/talos/talos_from_code.py
@@ -9,11 +9,12 @@
 # Author(s):     Zambrano Gasparnian, Armen <armenzg@mozilla.com>
 # Target:        Python 2.5
 #
+from __future__ import print_function
 from optparse import OptionParser
 import json
 import re
-import urllib2
-import urlparse
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
+import six.moves.urllib.parse
 import sys
 import os
 
@@ -40,27 +41,27 @@ def main():
         jsonFilename = download_file(options.talos_json_url)
     except Exception as e:
         print("ERROR: We tried to download the talos.json file but something failed.")
-        print("ERROR: %s" % str(e))
+        print(("ERROR: %s" % str(e)))
         sys.exit(1)
 
     # 3) download the necessary files
-    print("INFO: talos.json URL: %s" % options.talos_json_url)
+    print(("INFO: talos.json URL: %s" % options.talos_json_url))
     try:
         key = 'talos.zip'
         entity = get_value(jsonFilename, key)
         if passesRestrictions(options.talos_json_url, entity["url"]):
             # the key is at the same time the filename e.g. talos.zip
-            print("INFO: Downloading %s as %s" %
-                  (entity["url"], os.path.join(entity["path"], key)))
+            print(("INFO: Downloading %s as %s" %
+                  (entity["url"], os.path.join(entity["path"], key))))
             download_file(entity["url"], entity["path"], key)
         else:
-            print("ERROR: You have tried to download a file " +
+            print(("ERROR: You have tried to download a file " +
                   "from: %s " % entity["url"] +
-                  "which is a location different than http://talos-bundles.pvt.build.mozilla.org/")
+                  "which is a location different than http://talos-bundles.pvt.build.mozilla.org/"))
             print("ERROR: This is only allowed for the certain branches.")
             sys.exit(1)
     except Exception as e:
-        print("ERROR: %s" % str(e))
+        print(("ERROR: %s" % str(e)))
         sys.exit(1)
 
 
@@ -88,12 +89,12 @@ def get_filename_from_url(url):
     '''
     This returns the filename of the file we're trying to download
     '''
-    parsed = urlparse.urlsplit(url.rstrip('/'))
+    parsed = six.moves.urllib.parse.urlsplit(url.rstrip('/'))
     if parsed.path != '':
         return parsed.path.rsplit('/', 1)[-1]
     else:
-        print("ERROR: We were trying to download a file from %s " +
-              "but the URL seems to be incorrect.")
+        print(("ERROR: We were trying to download a file from %s " +
+              "but the URL seems to be incorrect."))
         sys.exit(1)
 
 
@@ -101,14 +102,14 @@ def download_file(url, path="", saveAs=None):
     '''
     It downloads a file from URL to the indicated path
     '''
-    req = urllib2.Request(url)
-    f = urllib2.urlopen(req)
+    req = six.moves.urllib.request.Request(url)
+    f = six.moves.urllib.request.urlopen(req)
     if path != "" and not os.path.isdir(path):
         try:
             os.makedirs(path)
-            print("INFO: directory %s created" % path)
+            print(("INFO: directory %s created" % path))
         except Exception as e:
-            print("ERROR: %s" % str(e))
+            print(("ERROR: %s" % str(e)))
             sys.exit(1)
     filename = saveAs if saveAs else get_filename_from_url(url)
     local_file = open(os.path.join(path, filename), 'wb')
diff --git a/testing/talos/tests/test_browser_output.py b/testing/talos/tests/test_browser_output.py
index 7b95733c01..ee837bb059 100644
--- a/testing/talos/tests/test_browser_output.py
+++ b/testing/talos/tests/test_browser_output.py
@@ -52,7 +52,7 @@ class TestBrowserOutput(unittest.TestCase):
         pageloader_results = PageloaderResults(raw_report)
         self.assertEqual(len(pageloader_results.results), 12)
         indices = [i['index'] for i in pageloader_results.results]
-        self.assertEqual(indices, range(12))
+        self.assertEqual(indices, list(range(12)))
 
         # test hixie-001.xml just as a spot-check
         hixie_001 = pageloader_results.results[5]
diff --git a/testing/talos/tests/test_filter.py b/testing/talos/tests/test_filter.py
index b4e2d39cf9..cbe9e5c7f1 100755
--- a/testing/talos/tests/test_filter.py
+++ b/testing/talos/tests/test_filter.py
@@ -12,7 +12,7 @@ import talos.filter
 
 class TestFilter(unittest.TestCase):
 
-    data = range(30)  # test data
+    data = list(range(30))  # test data
 
     def test_ignore(self):
         """test the ignore filter"""
diff --git a/testing/talos/tests/test_results.py b/testing/talos/tests/test_results.py
index 015da8ed26..cb5985435b 100755
--- a/testing/talos/tests/test_results.py
+++ b/testing/talos/tests/test_results.py
@@ -44,7 +44,7 @@ class TestPageloaderResults(unittest.TestCase):
 
         # test the indices
         indices = [i['index'] for i in results.results]
-        self.assertEqual(indices, range(12))
+        self.assertEqual(indices, list(range(12)))
 
         # test some pages
         pages = [i['page'] for i in results.results]
diff --git a/testing/tools/autotry/autotry.py b/testing/tools/autotry/autotry.py
index 7b0350b610..5c359c09c1 100644
--- a/testing/tools/autotry/autotry.py
+++ b/testing/tools/autotry/autotry.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import argparse
 import itertools
 import os
@@ -12,7 +13,8 @@ import which
 
 from collections import defaultdict
 
-import ConfigParser
+import six.moves.configparser
+import six
 
 
 def arg_parser():
@@ -96,7 +98,7 @@ class TryArgumentParser(object):
 
     def consume(self):
         try:
-            self.token = self.tokens.next()
+            self.token = next(self.tokens)
         except StopIteration:
             self.token = (self.EOF, None)
 
@@ -277,14 +279,14 @@ class AutoTry(object):
         return os.path.join(self.mach_context.state_dir, "autotry.ini")
 
     def load_config(self, name):
-        config = ConfigParser.RawConfigParser()
+        config = six.moves.configparser.RawConfigParser()
         success = config.read([self.config_path])
         if not success:
             return None
 
         try:
             data = config.get("try", name)
-        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+        except (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
             return None
 
         kwargs = vars(arg_parser().parse_args(self.split_try_string(data)))
@@ -292,21 +294,21 @@ class AutoTry(object):
         return kwargs
 
     def list_presets(self):
-        config = ConfigParser.RawConfigParser()
+        config = six.moves.configparser.RawConfigParser()
         success = config.read([self.config_path])
 
         data = []
         if success:
             try:
                 data = config.items("try")
-            except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+            except (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
                 pass
 
         if not data:
             print("No presets found")
 
         for name, try_string in data:
-            print("%s: %s" % (name, try_string))
+            print(("%s: %s" % (name, try_string)))
 
     def split_try_string(self, data):
         return re.findall(r'(?:\[.*?\]|\S)+', data)
@@ -315,7 +317,7 @@ class AutoTry(object):
         assert data.startswith("try: ")
         data = data[len("try: "):]
 
-        parser = ConfigParser.RawConfigParser()
+        parser = six.moves.configparser.RawConfigParser()
         parser.read([self.config_path])
 
         if not parser.has_section("try"):
@@ -388,7 +390,7 @@ class AutoTry(object):
 
         suites = tests if not intersection else {}
         paths = set()
-        for flavor, flavor_tests in paths_by_flavor.iteritems():
+        for flavor, flavor_tests in paths_by_flavor.items():
             suite = self.flavor_suites[flavor]
             if suite not in suites and (not intersection or suite in tests):
                 for job_name in self.flavor_jobs[flavor]:
@@ -423,7 +425,7 @@ class AutoTry(object):
             parts.append("--try-test-paths %s" % " ".join(sorted(paths)))
 
         args_by_dest = {v['dest']: k for k, v in AutoTry.pass_through_arguments.items()}
-        for dest, value in extras.iteritems():
+        for dest, value in extras.items():
             assert dest in args_by_dest
             arg = args_by_dest[dest]
             action = AutoTry.pass_through_arguments[arg]['action']
@@ -438,7 +440,7 @@ class AutoTry(object):
                 parts.append(arg)
 
         try_syntax = " ".join(parts)
-        if extras.get('artifact') and 'all' in suites.keys():
+        if extras.get('artifact') and 'all' in list(suites.keys()):
             message = ('You asked for |-u all| with |--artifact| but compiled-code tests ({tests})'
                        ' can\'t run against an artifact build. Try listing the suites you want'
                        ' instead. For example, this syntax covers most suites:\n{try_syntax}')
@@ -457,8 +459,8 @@ class AutoTry(object):
         args = ['git'] + list(args)
         ret = subprocess.call(args)
         if ret:
-            print('ERROR git command %s returned %s' %
-                  (args, ret))
+            print(('ERROR git command %s returned %s' %
+                  (args, ret)))
             sys.exit(1)
 
     def _git_push_to_try(self, msg):
@@ -485,8 +487,8 @@ class AutoTry(object):
             return subprocess.check_output(args).strip('\0').split('\0')
         except subprocess.CalledProcessError as e:
             print('Failed while determining files changed on this branch')
-            print('Failed whle running: %s' % args)
-            print(e.output)
+            print(('Failed whle running: %s' % args))
+            print((e.output))
             sys.exit(1)
 
     def _hg_find_changed_files(self):
@@ -501,8 +503,8 @@ class AutoTry(object):
         except subprocess.CalledProcessError as e:
             print('Failed while finding files changed since the last '
                   'public ancestor')
-            print('Failed whle running: %s' % hg_args)
-            print(e.output)
+            print(('Failed whle running: %s' % hg_args))
+            print((e.output))
             sys.exit(1)
 
     def find_changed_files(self):
@@ -521,7 +523,7 @@ class AutoTry(object):
                 hg_args = ['hg', 'push-to-try', '-m', msg]
                 subprocess.check_call(hg_args, stderr=subprocess.STDOUT)
             except subprocess.CalledProcessError as e:
-                print('ERROR hg command %s returned %s' % (hg_args, e.returncode))
+                print(('ERROR hg command %s returned %s' % (hg_args, e.returncode)))
                 print('\nmach failed to push to try. There may be a problem '
                       'with your ssh key, or another issue with your mercurial '
                       'installation.')
@@ -560,8 +562,8 @@ class AutoTry(object):
         changed_files = self.find_changed_files()
         if changed_files:
             if verbose:
-                print("Pushing tests based on modifications to the "
-                      "following files:\n\t%s" % "\n\t".join(changed_files))
+                print(("Pushing tests based on modifications to the "
+                      "following files:\n\t%s" % "\n\t".join(changed_files)))
 
             from mozbuild.frontend.reader import (
                 BuildReader,
@@ -578,9 +580,9 @@ class AutoTry(object):
 
             if verbose:
                 if paths:
-                    print("Pushing tests based on the following patterns:\n\t%s" %
-                          "\n\t".join(paths))
+                    print(("Pushing tests based on the following patterns:\n\t%s" %
+                          "\n\t".join(paths)))
                 if tags:
-                    print("Pushing tests based on the following tags:\n\t%s" %
-                          "\n\t".join(tags))
+                    print(("Pushing tests based on the following tags:\n\t%s" %
+                          "\n\t".join(tags)))
         return paths, tags
diff --git a/testing/tools/iceserver/iceserver.py b/testing/tools/iceserver/iceserver.py
index 85d0f3ee54..cd5134c971 100644
--- a/testing/tools/iceserver/iceserver.py
+++ b/testing/tools/iceserver/iceserver.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import ipaddr
 import socket
 import hmac
@@ -18,6 +19,7 @@ from string import Template
 from twisted.internet import reactor, protocol
 from twisted.internet.task import LoopingCall
 from twisted.internet.address import IPv4Address
+from functools import reduce
 
 MAGIC_COOKIE = 0x2112A442
 
@@ -321,7 +323,7 @@ class StunMessage(object):
         digest_buf = self.build(MESSAGE_INTEGRITY)
         # Trim off the MESSAGE-INTEGRITY attr
         digest_buf = digest_buf[:len(digest_buf) - 24]
-        password = passlib.utils.saslprep(unicode(password))
+        password = passlib.utils.saslprep(str(password))
         key_string = "{}:{}:{}".format(username, realm, password)
         md5 = hashlib.md5()
         md5.update(key_string)
@@ -367,10 +369,11 @@ class Allocation(protocol.DatagramProtocol):
         self.expiry = time.time()
         self.port = reactor.listenUDP(0, self, interface=v4_address)
 
-    def datagramReceived(self, data, (host, port)):
+    def datagramReceived(self, data, xxx_todo_changeme):
+        (host, port) = xxx_todo_changeme
         if not host in self.permissions:
-            print("Dropping packet from {}:{}, no permission on allocation {}"
-                  .format(host, port, self.transport.getHost()))
+            print(("Dropping packet from {}:{}, no permission on allocation {}"
+                  .format(host, port, self.transport.getHost())))
             return
 
         data_indication = StunMessage()
@@ -421,13 +424,13 @@ class StunHandler(object):
             if stun_message.method == SEND:
                 self.handle_send_indication(stun_message)
             else:
-                print("Dropping unknown indication method: {}"
-                      .format(stun_message.method))
+                print(("Dropping unknown indication method: {}"
+                      .format(stun_message.method)))
             return None
 
         if stun_message.msg_class != REQUEST:
-            print("Dropping STUN response, method: {}"
-                  .format(stun_message.method))
+            print(("Dropping STUN response, method: {}"
+                  .format(stun_message.method)))
             return None
 
         if stun_message.method == BINDING:
@@ -559,8 +562,8 @@ class StunHandler(object):
         try:
             allocation = allocations[self.get_allocation_tuple()]
         except KeyError:
-            print("Dropping send indication; no allocation for tuple {}"
-                  .format(self.get_allocation_tuple()))
+            print(("Dropping send indication; no allocation for tuple {}"
+                  .format(self.get_allocation_tuple())))
             return
 
         peer_address = indication.get_xor_address(XOR_PEER_ADDRESS)
@@ -578,8 +581,8 @@ class StunHandler(object):
             return
 
         if not peer_address.host in allocation.permissions:
-            print("Dropping send indication, no permission for {} on tuple {}"
-                  .format(peer_address.host, self.get_allocation_tuple()))
+            print(("Dropping send indication, no permission for {} on tuple {}"
+                  .format(peer_address.host, self.get_allocation_tuple())))
             return
 
         allocation.transport.write(data_attr.data,
@@ -594,7 +597,7 @@ class StunHandler(object):
 
     def make_error_response(self, request, code, reason=None):
         if reason:
-            print("{}: rejecting with {}".format(reason, code))
+            print(("{}: rejecting with {}".format(reason, code)))
         response = copy.deepcopy(request)
         response.attributes = []
         response.add_error_code(code, reason)
@@ -676,12 +679,12 @@ class TcpStunHandler(protocol.Protocol):
         self.stun_handler.data_received(data, self.address)
 
     def connectionLost(self, reason):
-        print("Lost connection from {}".format(self.address))
+        print(("Lost connection from {}".format(self.address)))
         # Destroy allocations that this connection made
         for key, allocation in allocations.items():
             if allocation.other_transport_handler == self:
-                print("Closing allocation due to dropped connection: {}"
-                      .format(key))
+                print(("Closing allocation due to dropped connection: {}"
+                      .format(key)))
                 del allocations[key]
                 allocation.close()
 
@@ -713,7 +716,7 @@ def prune_allocations():
     now = time.time()
     for key, allocation in allocations.items():
         if allocation.expiry < now:
-            print("Allocation expired: {}".format(key))
+            print(("Allocation expired: {}".format(key)))
             del allocations[key]
             allocation.close()
 
@@ -789,7 +792,7 @@ if __name__ == "__main__":
         lines = f.readlines();
         lines.pop(0); # Remove BEGIN CERTIFICATE
         lines.pop(); # Remove END CERTIFICATE
-        lines = map(string.strip, lines);
+        lines = list(map(string.strip, lines));
         certbase64 = string.join(lines, '');
 
         turns_url = ', "turns:' + hostname + '"'
@@ -810,11 +813,11 @@ if __name__ == "__main__":
 $cert_prop}]' # Hack to make it easier to override cert checks
 )
 
-    print(template.substitute(user=turn_user,
+    print((template.substitute(user=turn_user,
                               pwd=turn_pass,
                               hostname=hostname,
                               turns_url=turns_url,
-                              cert_prop=cert_prop))
+                              cert_prop=cert_prop)))
 
     reactor.run()
 
diff --git a/testing/tools/proxyserver/proxyserver.py b/testing/tools/proxyserver/proxyserver.py
index d7b2ef1610..a210fcff9b 100644
--- a/testing/tools/proxyserver/proxyserver.py
+++ b/testing/tools/proxyserver/proxyserver.py
@@ -45,6 +45,7 @@ TODO:
   items from the database and such.
 """
 
+from __future__ import print_function
 __version__ = "0.1"
 
 import os
@@ -54,13 +55,13 @@ import threading
 import shelve
 from optparse import OptionParser, OptionValueError
 
-import SocketServer
-import BaseHTTPServer
+import six.moves.socketserver
+import six.moves.BaseHTTPServer
 import socket
-import httplib
-from urlparse import urlsplit, urlunsplit
+import six.moves.http_client
+from urllib.parse import urlsplit, urlunsplit
 
-class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+class HTTPRequestHandler(six.moves.BaseHTTPServer.BaseHTTPRequestHandler):
   server_version = "TalosProxy/" + __version__
   protocol_version = "HTTP/1.1"
 
@@ -69,9 +70,9 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     if content:
       try:
         self.wfile.write(content)
-      except socket.error, e:
+      except socket.error as e:
         if options.verbose:
-          print "Got socket error %s" % e
+          print("Got socket error %s" % e)
     #self.close_connection = 1
   def do_HEAD(self):
     self.send_head()
@@ -108,8 +109,8 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
         return None
       else:
         if options.verbose:
-          print "Object %s was not in the cache" % self.path
-        conn = httplib.HTTPConnection(o.netloc)
+          print("Object %s was not in the cache" % self.path)
+        conn = six.moves.http_client.HTTPConnection(o.netloc)
         conn.request("GET", reqstring, headers=headers)
         res = conn.getresponse()
 
@@ -133,18 +134,18 @@ class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
       if "Content-Length" not in headers:
         self.send_header("Content-Length", str(len(content)))
       self.end_headers()
-    except socket.error, e:
+    except socket.error as e:
       if options.verbose:
-        print "Got socket error %s" % e
+        print("Got socket error %s" % e)
       return None
     return content
   def log_message(self, format, *args):
     if options.verbose:
-      BaseHTTPServer.BaseHTTPRequestHandler.log_message(self, format, *args)
+      six.moves.BaseHTTPServer.BaseHTTPRequestHandler.log_message(self, format, *args)
 
-class HTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
+class HTTPServer(six.moves.socketserver.ThreadingMixIn, six.moves.BaseHTTPServer.HTTPServer):
   def __init__(self, address, handler):
-    BaseHTTPServer.HTTPServer.__init__(self, address, handler)
+    six.moves.BaseHTTPServer.HTTPServer.__init__(self, address, handler)
 
 class Cache(object):
   """Multithreaded cache uses the shelve module to store pages"""
@@ -176,7 +177,7 @@ class Cache(object):
     self.sem.acquire()
     self.semlock.release()
     try:
-      if not self.db.has_key(key):
+      if key not in self.db:
         return None
       # returns status, headers, content
       return self.db[key]
@@ -264,6 +265,6 @@ if __name__ == '__main__':
     while 1: time.sleep(1)
   except KeyboardInterrupt:
     if options.verbose:
-      print "Quittin' time..."
+      print("Quittin' time...")
 
 __all__ = ['run_proxy', 'configure_proxy']
diff --git a/testing/tools/websocketprocessbridge/websocketprocessbridge.py b/testing/tools/websocketprocessbridge/websocketprocessbridge.py
index 02418d0e67..3df0ec2d26 100644
--- a/testing/tools/websocketprocessbridge/websocketprocessbridge.py
+++ b/testing/tools/websocketprocessbridge/websocketprocessbridge.py
@@ -2,6 +2,7 @@
 # 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 print_function
 from twisted.internet import protocol, reactor
 from twisted.internet.task import LoopingCall
 import txws
@@ -99,7 +100,7 @@ if __name__ == "__main__":
 
     bridgeFactory = ProcessSocketBridgeFactory()
     reactor.listenTCP(int(args.port), txws.WebSocketFactory(bridgeFactory))
-    print("websocket/process bridge listening on port %s" % args.port)
+    print(("websocket/process bridge listening on port %s" % args.port))
     reactor.run()
 
 
diff --git a/testing/tps/create_venv.py b/testing/tps/create_venv.py
index 3d5417f8af..82139b9d4c 100755
--- a/testing/tps/create_venv.py
+++ b/testing/tps/create_venv.py
@@ -9,13 +9,15 @@ It's probably best to specify a path NOT inside the repo, otherwise
 all the virtualenv files will show up in e.g. hg status.
 """
 
+from __future__ import print_function
 import optparse
 import os
 import shutil
 import subprocess
 import sys
-import urllib2
+import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 import zipfile
+import six
 
 
 here = os.path.dirname(os.path.abspath(__file__))
@@ -53,7 +55,7 @@ else:
 
 def download(url, target):
     """Downloads the specified url to the given target."""
-    response = urllib2.urlopen(url)
+    response = six.moves.urllib.request.urlopen(url)
     with open(target, 'wb') as f:
         f.write(response.read())
 
@@ -64,7 +66,7 @@ def setup_virtualenv(target, python_bin=None):
     script_path = os.path.join(here, 'virtualenv-%s' % VERSION_VIRTUALENV,
                                'virtualenv.py')
 
-    print 'Downloading virtualenv %s' % VERSION_VIRTUALENV
+    print('Downloading virtualenv %s' % VERSION_VIRTUALENV)
     zip_path = download(URL_VIRTUALENV + VERSION_VIRTUALENV,
                         os.path.join(here, 'virtualenv.zip'))
 
@@ -72,7 +74,7 @@ def setup_virtualenv(target, python_bin=None):
         with zipfile.ZipFile(zip_path, 'r') as f:
             f.extractall(here)
 
-        print 'Creating new virtual environment'
+        print('Creating new virtual environment')
         cmd_args = [sys.executable, script_path, target]
 
         if python_bin:
@@ -93,7 +95,7 @@ def update_configfile(source, target, replacements):
 
     with open(source) as config:
         for line in config:
-            for source_string, target_string in replacements.iteritems():
+            for source_string, target_string in replacements.items():
                 if target_string:
                     line = line.replace(source_string, target_string)
             lines.append(line)
@@ -153,7 +155,7 @@ def main():
 
     # Activate tps environment
     tps_env = os.path.join(target, activate_env)
-    execfile(tps_env, dict(__file__=tps_env))
+    exec(compile(open(tps_env, "rb").read(), tps_env, 'exec'), dict(__file__=tps_env))
 
     # Install TPS in environment
     subprocess.check_call([os.path.join(target, python_env),
@@ -182,13 +184,13 @@ def main():
                       '__SYNC_ACCOUNT_PASSPHRASE__': options.sync_passphrase})
 
     if not (options.username and options.password):
-        print '\nFirefox Account credentials not specified.'
+        print('\nFirefox Account credentials not specified.')
     if not (options.sync_username and options.sync_password and options.passphrase):
-        print '\nFirefox Sync account credentials not specified.'
+        print('\nFirefox Sync account credentials not specified.')
 
     # Print the user instructions
-    print usage_message.format(TARGET=target,
-                               BIN_NAME=bin_name)
+    print(usage_message.format(TARGET=target,
+                               BIN_NAME=bin_name))
 
 if __name__ == "__main__":
     main()
diff --git a/testing/tps/tps/cli.py b/testing/tps/tps/cli.py
index 63e8db0d40..81bdea4791 100644
--- a/testing/tps/tps/cli.py
+++ b/testing/tps/tps/cli.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import json
 import optparse
 import os
@@ -93,7 +94,7 @@ def main():
 
     rlock = RLock()
 
-    print 'using result file', options.resultfile
+    print('using result file', options.resultfile)
 
     extensionDir = config.get('extensiondir')
     if not extensionDir or extensionDir == '__EXTENSIONDIR__':
diff --git a/testing/tps/tps/firefoxrunner.py b/testing/tps/tps/firefoxrunner.py
index 3b7c143d89..7bf6ed30eb 100644
--- a/testing/tps/tps/firefoxrunner.py
+++ b/testing/tps/tps/firefoxrunner.py
@@ -3,6 +3,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
+from __future__ import print_function
 import copy
 import httplib2
 import os
@@ -53,11 +54,11 @@ class TPSFirefoxRunner(object):
             os.remove(pathToBuild)
 
         # download the build
-        print 'downloading build'
+        print('downloading build')
         self.download_url(self.url, pathToBuild)
 
         # install the build
-        print 'installing %s' % pathToBuild
+        print('installing %s' % pathToBuild)
         mozfile.remove(self.installdir, True)
         binary = mozinstall.install(src=pathToBuild, dest=self.installdir)
 
diff --git a/testing/tps/tps/testrunner.py b/testing/tps/tps/testrunner.py
index 8e5aee6c83..fe0b367196 100644
--- a/testing/tps/tps/testrunner.py
+++ b/testing/tps/tps/testrunner.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import json
 import os
 import platform
@@ -164,7 +165,7 @@ class TPSTestRunner(object):
         f.write(msg)
         f.close()
         if printToConsole:
-            print msg
+            print(msg)
 
     def writeToResultFile(self, postdata, body=None,
                           sendTo=['crossweave@mozilla.com']):
@@ -347,7 +348,7 @@ class TPSTestRunner(object):
 
         self.log(logstr, True)
         for phase in phaselist:
-            print "\t%s: %s" % (phase.phase, phase.status)
+            print("\t%s: %s" % (phase.phase, phase.status))
 
         return resultdata
 
@@ -428,9 +429,9 @@ class TPSTestRunner(object):
             self.rlock.release()
 
         # dump out a summary of test results
-        print 'Test Summary\n'
+        print('Test Summary\n')
         for test in self.postdata.get('tests', {}):
-            print '%s | %s | %s' % (test['state'], test['name'], test['message'])
+            print('%s | %s | %s' % (test['state'], test['name'], test['message']))
 
     def run_test_group(self):
         self.results = []
@@ -476,7 +477,7 @@ class TPSTestRunner(object):
             else:
                 self.numfailed += 1
                 if self.stop_on_error:
-                    print '\nTest failed with --stop-on-error specified; not running any more tests.\n'
+                    print('\nTest failed with --stop-on-error specified; not running any more tests.\n')
                     break
 
         self.mozhttpd.stop()
diff --git a/testing/xpcshell/mach_commands.py b/testing/xpcshell/mach_commands.py
index d821ff46fb..dc6033cdd5 100644
--- a/testing/xpcshell/mach_commands.py
+++ b/testing/xpcshell/mach_commands.py
@@ -29,7 +29,7 @@ from xpcshellcommandline import parser_desktop, parser_remote
 here = os.path.abspath(os.path.dirname(__file__))
 
 if sys.version_info[0] < 3:
-    unicode_type = unicode
+    unicode_type = str
 else:
     unicode_type = str
 
@@ -124,7 +124,7 @@ class XPCShellRunner(MozbuildObject):
         # Python through 2.7.2 has issues with unicode in some of the
         # arguments. Work around that.
         filtered_args = {}
-        for k, v in kwargs.iteritems():
+        for k, v in kwargs.items():
             if isinstance(v, unicode_type):
                 v = v.encode('utf-8')
 
diff --git a/testing/xpcshell/mach_test_package_commands.py b/testing/xpcshell/mach_test_package_commands.py
index fc7d273859..c8a8169026 100644
--- a/testing/xpcshell/mach_test_package_commands.py
+++ b/testing/xpcshell/mach_test_package_commands.py
@@ -44,7 +44,7 @@ def run_xpcshell(context, **kwargs):
     if args.testPaths:
         test_root = os.path.join(context.package_root, 'xpcshell', 'tests')
         normalize = partial(context.normalize_test_path, test_root)
-        args.testPaths = map(normalize, args.testPaths)
+        args.testPaths = list(map(normalize, args.testPaths))
 
     import runxpcshelltests
     xpcshell = runxpcshelltests.XPCShellTests(log=log)
diff --git a/testing/xpcshell/remotexpcshelltests.py b/testing/xpcshell/remotexpcshelltests.py
index c5124880f8..91f7dd1d6a 100644
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import posixpath
 import sys, os
 import subprocess
@@ -169,7 +170,7 @@ class RemoteXPCShellTestThread(xpcshell.XPCShellTestThread):
             # The minidumps directory is automatically created when Fennec
             # (first) starts, so its lack of presence is a hint that
             # something went wrong.
-            print "Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir
+            print("Automation Error: No crash directory (%s) found on remote device" % self.remoteMinidumpDir)
             # Whilst no crash was found, the run should still display as a failure
             return True
         with mozfile.TemporaryDirectory() as dumpDir:
@@ -276,7 +277,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
         elif os.path.isdir(os.path.join(here, 'tests')):
             self.xpcDir = os.path.join(here, 'tests')
         else:
-            print >> sys.stderr, "Couldn't find local xpcshell test directory"
+            print("Couldn't find local xpcshell test directory", file=sys.stderr)
             sys.exit(1)
 
         if options.localAPK:
@@ -321,7 +322,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
         localWrapper = tempfile.mktemp()
         f = open(localWrapper, "w")
         f.write("#!/system/bin/sh\n")
-        for envkey, envval in self.env.iteritems():
+        for envkey, envval in self.env.items():
             f.write("export %s=%s\n" % (envkey, envval))
         f.writelines([
             "cd $1\n",
@@ -376,7 +377,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
                 if packageName:
                     self.appRoot = self.device.getAppRoot(packageName.strip())
             except Exception as detail:
-                print "unable to determine app root: " + str(detail)
+                print("unable to determine app root: " + str(detail))
                 pass
         return None
 
@@ -418,11 +419,11 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
         for fname in binaries:
             local = os.path.join(self.localBin, fname)
             if os.path.isfile(local):
-                print >> sys.stderr, "Pushing %s.." % fname
+                print("Pushing %s.." % fname, file=sys.stderr)
                 remoteFile = remoteJoin(self.remoteBinDir, fname)
                 self.device.pushFile(local, remoteFile)
             else:
-                print >> sys.stderr, "*** Expected binary %s not found in %s!" % (fname, self.localBin)
+                print("*** Expected binary %s not found in %s!" % (fname, self.localBin), file=sys.stderr)
 
         local = os.path.join(self.localBin, "components/httpd.js")
         remoteFile = remoteJoin(self.remoteComponentsDir, "httpd.js")
@@ -449,7 +450,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
                 dir = tempfile.mkdtemp()
                 for info in self.localAPKContents.infolist():
                     if info.filename.endswith(".so"):
-                        print >> sys.stderr, "Pushing %s.." % info.filename
+                        print("Pushing %s.." % info.filename, file=sys.stderr)
                         remoteFile = remoteJoin(self.remoteBinDir, os.path.basename(info.filename))
                         self.localAPKContents.extract(info, dir)
                         localFile = os.path.join(dir, info.filename)
@@ -468,9 +469,9 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
 
         for file in os.listdir(self.localLib):
             if (file.endswith(".so")):
-                print >> sys.stderr, "Pushing %s.." % file
+                print("Pushing %s.." % file, file=sys.stderr)
                 if 'libxul' in file:
-                    print >> sys.stderr, "This is a big file, it could take a while."
+                    print("This is a big file, it could take a while.", file=sys.stderr)
                 localFile = os.path.join(self.localLib, file)
                 remoteFile = remoteJoin(self.remoteBinDir, file)
                 self.device.pushFile(localFile, remoteFile)
@@ -482,7 +483,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
             for root, dirs, files in os.walk(localArmLib):
                 for file in files:
                     if (file.endswith(".so")):
-                        print >> sys.stderr, "Pushing %s.." % file
+                        print("Pushing %s.." % file, file=sys.stderr)
                         localFile = os.path.join(root, file)
                         remoteFile = remoteJoin(self.remoteBinDir, file)
                         self.device.pushFile(localFile, remoteFile)
@@ -495,7 +496,7 @@ class XPCShellRemote(xpcshell.XPCShellTests, object):
             self.device.pushDir(self.testingModulesDir, self.remoteModulesDir)
 
     def setupTestDir(self):
-        print 'pushing %s' % self.xpcDir
+        print('pushing %s' % self.xpcDir)
         try:
             # The tests directory can be quite large: 5000 files and growing!
             # Sometimes - like on a low-end aws instance running an emulator - the push
@@ -560,7 +561,7 @@ class PathMapping:
 
 def main():
     if sys.version_info < (2,7):
-        print >>sys.stderr, "Error: You must use python version 2.7 or newer but less than 3.0"
+        print("Error: You must use python version 2.7 or newer but less than 3.0", file=sys.stderr)
         sys.exit(1)
 
     parser = parser_remote()
@@ -570,10 +571,10 @@ def main():
             if (file.endswith(".apk") and file.startswith("fennec")):
                 options.localAPK = os.path.join(options.objdir, "dist")
                 options.localAPK = os.path.join(options.localAPK, file)
-                print >>sys.stderr, "using APK: " + options.localAPK
+                print("using APK: " + options.localAPK, file=sys.stderr)
                 break
         else:
-            print >>sys.stderr, "Error: please specify an APK"
+            print("Error: please specify an APK", file=sys.stderr)
             sys.exit(1)
 
     options = verifyRemoteOptions(parser, options)
@@ -588,12 +589,12 @@ def main():
             dm = mozdevice.DroidADB(packageName=None, deviceRoot=options.remoteTestRoot)
     else:
         if not options.deviceIP:
-            print "Error: you must provide a device IP to connect to via the --device option"
+            print("Error: you must provide a device IP to connect to via the --device option")
             sys.exit(1)
         dm = mozdevice.DroidSUT(options.deviceIP, options.devicePort, deviceRoot=options.remoteTestRoot)
 
     if options.interactive and not options.testPath:
-        print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
+        print("Error: You must specify a test filename in interactive mode!", file=sys.stderr)
         sys.exit(1)
 
     if options.xpcshell is None:
diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py
index 34af6639fb..97eec4f836 100755
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import copy
 import importlib
 import json
@@ -24,7 +25,31 @@ import traceback
 
 from collections import deque, namedtuple
 from distutils import dir_util
-from distutils.version import LooseVersion
+try:
+    from distutils.version import LooseVersion
+except ImportError:
+    import re as _re
+    class LooseVersion:
+        def __init__(self, vstring):
+            self.vstring = vstring
+            self.version = [int(x) if x.isdigit() else x for x in _re.split(r'[.\-]', vstring)]
+        def __str__(self): return self.vstring
+        def __repr__(self): return "LooseVersion ('%s')" % str(self)
+        def _cmp(self, other):
+            if not isinstance(other, LooseVersion): other = LooseVersion(other)
+            a, b = self.version, other.version
+            for i in range(max(len(a), len(b))):
+                va = a[i] if i < len(a) else 0
+                vb = b[i] if i < len(b) else 0
+                if type(va) != type(vb): va, vb = str(va), str(vb)
+                if va < vb: return -1
+                if va > vb: return 1
+            return 0
+        def __eq__(self, other): return self._cmp(other) == 0
+        def __lt__(self, other): return self._cmp(other) < 0
+        def __le__(self, other): return self._cmp(other) <= 0
+        def __gt__(self, other): return self._cmp(other) > 0
+        def __ge__(self, other): return self._cmp(other) >= 0
 from multiprocessing import cpu_count
 from argparse import ArgumentParser
 from subprocess import Popen, PIPE, STDOUT
@@ -91,9 +116,9 @@ def cleanup_encoding(s):
        points, etc.  If it is a byte string, it is assumed to be
        UTF-8, but it may not be *correct* UTF-8.  Return a
        sanitized unicode object."""
-    if not isinstance(s, basestring):
-        return unicode(s)
-    if not isinstance(s, unicode):
+    if not isinstance(s, str):
+        return str(s)
+    if not isinstance(s, str):
         s = s.decode('utf-8', 'replace')
     # Replace all C0 and C1 control characters with \xNN escapes.
     return _cleanup_encoding_re.sub(_cleanup_encoding_repl, s)
@@ -267,8 +292,8 @@ class XPCShellTestThread(Thread):
         self.log.info("%s | current directory: %r" % (name, testdir))
         # Show only those environment variables that are changed from
         # the ambient environment.
-        changedEnv = (set("%s=%s" % i for i in self.env.iteritems())
-                      - set("%s=%s" % i for i in os.environ.iteritems()))
+        changedEnv = (set("%s=%s" % i for i in self.env.items())
+                      - set("%s=%s" % i for i in os.environ.items()))
         self.log.info("%s | environment: %s" % (name, list(changedEnv)))
 
     def killTimeout(self, proc):
@@ -514,7 +539,7 @@ class XPCShellTestThread(Thread):
     def log_line(self, line):
         """Log a line of output (either a parser json object or text output from
         the test process"""
-        if isinstance(line, basestring):
+        if isinstance(line, str):
             line = self.fix_text_output(line).rstrip('\r\n')
             self.log.process_output(self.proc_ident,
                                     line,
@@ -822,8 +847,8 @@ class XPCShellTests(object):
         if os.path.exists(ini_path):
             return TestManifest([ini_path], strict=True)
         else:
-            print >> sys.stderr, ("Failed to find manifest at %s; use --manifest "
-                                  "to set path explicitly." % (ini_path,))
+            print(("Failed to find manifest at %s; use --manifest "
+                                  "to set path explicitly." % (ini_path,)), file=sys.stderr)
             sys.exit(1)
 
     def buildTestList(self, test_tags=None, test_paths=None):
@@ -1002,7 +1027,7 @@ class XPCShellTests(object):
                 # node did not support ALPN until this version.
                 if version >= LooseVersion("5.0.0"):
                     nodeBin = localPath
-            except (subprocess.CalledProcessError, OSError), e:
+            except (subprocess.CalledProcessError, OSError) as e:
                 self.log.error('Could not retrieve node version: %s' % str(e))
 
         if os.getenv('MOZ_ASSUME_NODE_RUNNING', None):
@@ -1030,7 +1055,7 @@ class XPCShellTests(object):
                             searchObj = re.search( r'HTTP2 server listening on port (.*)', msg, 0)
                             if searchObj:
                               self.env["MOZHTTP2_PORT"] = searchObj.group(1)
-                    except OSError, e:
+                    except OSError as e:
                         # This occurs if the subprocess couldn't be started
                         self.log.error('Could not run %s server: %s' % (name, str(e)))
 
@@ -1043,7 +1068,7 @@ class XPCShellTests(object):
         """
           Shut down our node process, if it exists
         """
-        for name, proc in self.nodeProc.iteritems():
+        for name, proc in self.nodeProc.items():
             self.log.info('Node %s server shutting down ...' % name)
             if proc.poll() is not None:
                 self.log.info('Node server %s already dead %s' % (name, proc.poll()))
@@ -1150,7 +1175,7 @@ class XPCShellTests(object):
                 os.remove(failure_manifest)
                 manifest = rerun_manifest
             else:
-                print >> sys.stderr, "No failures were found to re-run."
+                print("No failures were found to re-run.", file=sys.stderr)
                 sys.exit(1)
 
         if testingModulesDir:
@@ -1220,7 +1245,7 @@ class XPCShellTests(object):
         # All of the keys in question should be ASCII.
         fixedInfo = {}
         for k, v in self.mozInfo.items():
-            if isinstance(k, unicode):
+            if isinstance(k, str):
                 k = k.encode('ascii')
             fixedInfo[k] = v
         self.mozInfo = fixedInfo
@@ -1483,12 +1508,12 @@ def main():
     log = commandline.setup_logging("XPCShell", options, {"tbpl": sys.stdout})
 
     if options.xpcshell is None:
-        print >> sys.stderr, """Must provide path to xpcshell using --xpcshell"""
+        print("""Must provide path to xpcshell using --xpcshell""", file=sys.stderr)
 
     xpcsh = XPCShellTests(log)
 
     if options.interactive and not options.testPath:
-        print >>sys.stderr, "Error: You must specify a test filename in interactive mode!"
+        print("Error: You must specify a test filename in interactive mode!", file=sys.stderr)
         sys.exit(1)
 
     if not xpcsh.runTests(**vars(options)):
diff --git a/testing/xpcshell/selftest.py b/testing/xpcshell/selftest.py
index 071ab5eda6..711302188b 100755
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -447,7 +447,7 @@ class XPCShellTestsTests(unittest.TestCase):
         """
         testlines = []
         for t in tests:
-            testlines.append("[%s]" % (t if isinstance(t, basestring)
+            testlines.append("[%s]" % (t if isinstance(t, str)
                                        else t[0]))
             if isinstance(t, tuple):
                 testlines.extend(t[1:])
@@ -1041,7 +1041,7 @@ add_test({
         try:
             # The actual return value is never checked because we raise.
             self.assertTestResult(True)
-        except Exception, ex:
+        except Exception as ex:
             raised = True
             self.assertEquals(ex.message[0:9], "head file")
 
@@ -1058,7 +1058,7 @@ add_test({
 
         try:
             self.assertTestResult(True)
-        except Exception, ex:
+        except Exception as ex:
             raised = True
             self.assertEquals(ex.message[0:9], "tail file")
 
diff --git a/testing/xpcshell/xpcshellcommandline.py b/testing/xpcshell/xpcshellcommandline.py
index d2a8e6bc13..b106fa058f 100644
--- a/testing/xpcshell/xpcshellcommandline.py
+++ b/testing/xpcshell/xpcshellcommandline.py
@@ -5,7 +5,7 @@ from mozlog import commandline
 
 def add_common_arguments(parser):
     parser.add_argument("--app-path",
-                        type=unicode, dest="appPath", default=None,
+                        type=str, dest="appPath", default=None,
                         help="application directory (as opposed to XRE directory)")
     parser.add_argument("--interactive",
                         action="store_true", dest="interactive", default=False,
@@ -22,7 +22,7 @@ def add_common_arguments(parser):
     parser.add_argument("--dump-tests", type=str, dest="dump_tests", default=None,
                         help="Specify path to a filename to dump all the tests that will be run")
     parser.add_argument("--manifest",
-                        type=unicode, dest="manifest", default=None,
+                        type=str, dest="manifest", default=None,
                         help="Manifest of test directories to use")
     parser.add_argument("--no-logfiles",
                         action="store_false", dest="logfiles",
diff --git a/toolkit/library/dependentlibs.py b/toolkit/library/dependentlibs.py
index 958fe5ef1d..dabd18a50c 100644
--- a/toolkit/library/dependentlibs.py
+++ b/toolkit/library/dependentlibs.py
@@ -29,7 +29,7 @@ def dependentlibs_dumpbin(lib):
     deps = []
     for line in proc.stdout:
         # Each line containing an imported library name starts with 4 spaces
-        match = re.match('    (\S+)', line)
+        match = re.match(r'    (\S+)', line)
         if match:
              deps.append(match.group(1))
         elif len(deps):
@@ -44,7 +44,7 @@ def dependentlibs_mingw_objdump(lib):
     proc = subprocess.Popen(['objdump', '-x', lib], stdout = subprocess.PIPE)
     deps = []
     for line in proc.stdout:
-        match = re.match('\tDLL Name: (\S+)', line)
+        match = re.match('\tDLL Name: (\\S+)', line)
         if match:
             deps.append(match.group(1))
     proc.wait()
@@ -77,13 +77,15 @@ def dependentlibs_readelf(lib):
         # or with BSD readelf:
         #  tag TYPE            value
         # Looking for NEEDED type entries
+        if isinstance(line, bytes):
+            line = line.decode('utf-8', errors='replace')
         tmp = line.split(' ', 3)
         if len(tmp) > 3 and 'NEEDED' in tmp[2]:
             # NEEDED lines look like:
             # 0x00000001 (NEEDED)             Shared library: [libname]
             # or with BSD readelf:
             # 0x00000001 NEEDED               Shared library: [libname]
-            match = re.search('\[(.*)\]', tmp[3])
+            match = re.search(r'\[(.*)\]', tmp[3])
             if match:
                 deps.append(match.group(1))
     proc.wait()
@@ -149,7 +151,7 @@ def gen_list(output, lib):
 
     deps = dependentlibs(lib, libpaths, func)
     deps[lib] = mozpath.join(libpaths[0], lib)
-    output.write('\n'.join(deps.keys()) + '\n')
+    output.write('\n'.join(list(deps.keys())) + '\n')
     return set(deps.values())
 
 def main():
diff --git a/toolkit/mozapps/installer/find-dupes.py b/toolkit/mozapps/installer/find-dupes.py
index 34ef675f49..5fc3a11536 100644
--- a/toolkit/mozapps/installer/find-dupes.py
+++ b/toolkit/mozapps/installer/find-dupes.py
@@ -23,23 +23,23 @@ def find_dupes(source):
         md5s[m][1].append(p)
     total = 0
     num_dupes = 0
-    for m, (size, paths) in md5s.iteritems():
+    for m, (size, paths) in md5s.items():
         if len(paths) > 1:
-            print 'Duplicates %d bytes%s:' % (size,
-                  ' (%d times)' % (len(paths) - 1) if len(paths) > 2 else '')
-            print ''.join('  %s\n' % p for p in paths)
+            print('Duplicates %d bytes%s:' % (size,
+                  ' (%d times)' % (len(paths) - 1) if len(paths) > 2 else ''))
+            print(''.join('  %s\n' % p for p in paths))
             total += (len(paths) - 1) * size
             num_dupes += 1
     if num_dupes:
-        print "WARNING: Found %d duplicated files taking %d bytes" % \
-              (num_dupes, total) + " (uncompressed)"
+        print("WARNING: Found %d duplicated files taking %d bytes" % \
+              (num_dupes, total) + " (uncompressed)")
 
 
 def main():
     if len(sys.argv) != 2:
         import os
-        print >>sys.stderr, "Usage: %s directory" % \
-                            os.path.basename(sys.argv[0])
+        print("Usage: %s directory" % \
+                            os.path.basename(sys.argv[0]), file=sys.stderr)
         sys.exit(1)
 
     find_dupes(sys.argv[1])
diff --git a/toolkit/mozapps/installer/informulate.py b/toolkit/mozapps/installer/informulate.py
index 6af43ac685..eeb7989021 100644
--- a/toolkit/mozapps/installer/informulate.py
+++ b/toolkit/mozapps/installer/informulate.py
@@ -15,7 +15,7 @@ def parse_cmdline(args):
     for arg in args:
         key, s, value = arg.partition("=")
         if s == '':
-            print "ERROR: Malformed command line key value pairing (%s)" % arg
+            print("ERROR: Malformed command line key value pairing (%s)" % arg)
             exit(1)
         contents[key.lower()] = value
     return contents
@@ -23,7 +23,7 @@ def parse_cmdline(args):
 
 def main():
     if len(sys.argv) < 2:
-        print "ERROR: You must specify an output file"
+        print("ERROR: You must specify an output file")
         exit(1)
 
     all_key_value_pairs = {}
@@ -34,7 +34,7 @@ def main():
         'MOZ_APP_VERSION', 'MOZ_APP_MAXVERSION', 'MOZ_APP_ID',
         'CC', 'CXX', 'LD', 'AS']
 
-    all_key_value_pairs = dict([(x.lower(), buildconfig.substs[x]) for x in important_substitutions])
+    all_key_value_pairs = {x.lower(): buildconfig.substs[x] for x in important_substitutions}
     all_key_value_pairs.update(parse_cmdline(sys.argv[2:]))
 
     with open(sys.argv[1], "w+") as f:
diff --git a/toolkit/mozapps/installer/l10n-repack.py b/toolkit/mozapps/installer/l10n-repack.py
index fcf3e773cd..5d214d807f 100644
--- a/toolkit/mozapps/installer/l10n-repack.py
+++ b/toolkit/mozapps/installer/l10n-repack.py
@@ -13,7 +13,7 @@ import buildconfig
 
 # Set of files or directories not listed in a chrome.manifest but that are
 # localized.
-NON_CHROME = set([
+NON_CHROME = {
     '**/crashreporter*.ini',
     'searchplugins',
     'dictionaries',
@@ -24,7 +24,7 @@ NON_CHROME = set([
     'extensions/langpack-*@*',
     'distribution/extensions/langpack-*@*',
     'chrome/**/searchplugins/*.xml',
-])
+}
 
 
 def valid_extra_l10n(arg):
diff --git a/toolkit/mozapps/installer/packager.py b/toolkit/mozapps/installer/packager.py
index 42a66812f9..d75ce8ea6e 100644
--- a/toolkit/mozapps/installer/packager.py
+++ b/toolkit/mozapps/installer/packager.py
@@ -29,11 +29,11 @@ import mozpack.path as mozpath
 import buildconfig
 from argparse import ArgumentParser
 import os
-from StringIO import StringIO
+from io import StringIO
 import subprocess
 import platform
 
-class ToolLauncher(object):
+class ToolLauncher:
     '''
     Helper to execute tools like xpcshell with the appropriate environment.
         launcher = ToolLauncher()
@@ -75,16 +75,16 @@ class ToolLauncher(object):
 
                 vcdir = os.path.abspath(os.path.join(env[e], '../../VC/bin'))
                 if os.path.exists(vcdir):
-                    env['PATH'] = '%s;%s' % (vcdir, env['PATH'])
+                    env['PATH'] = '{};{}'.format(vcdir, env['PATH'])
                     break
 
         # Work around a bug in Python 2.7.2 and lower where unicode types in
         # environment variables aren't handled by subprocess.
         for k, v in env.items():
-            if isinstance(v, unicode):
+            if isinstance(v, str):
                 env[k] = v.encode('utf-8')
 
-        print >>errors.out, 'Executing', ' '.join(cmd)
+        print('Executing', ' '.join(cmd), file=errors.out)
         errors.out.flush()
         return subprocess.call(cmd, env=env)
 
@@ -138,10 +138,11 @@ def precompile_cache(registry, source_path, gre_path, app_path):
         jar = JarReader(cache)
         resource = '/resource/%s/' % resource
         for f in jar:
-            if resource in f.filename:
-                path = f.filename[f.filename.index(resource) + len(resource):]
+            filename = f.filename.decode('utf-8') if isinstance(f.filename, bytes) else f.filename
+            if resource in filename:
+                path = filename[filename.index(resource) + len(resource):]
                 if registry.contains(path):
-                    registry.add(f.filename, GeneratedFile(f.read()))
+                    registry.add(filename, GeneratedFile(f.read()))
         jar.close()
     finally:
         if os.path.exists(cache):
@@ -180,7 +181,7 @@ def split_define(define):
     return (define, 1)
 
 
-class NoPkgFilesRemover(object):
+class NoPkgFilesRemover:
     '''
     Formatter wrapper to handle NO_PKG_FILES.
     '''
diff --git a/toolkit/mozapps/installer/unpack.py b/toolkit/mozapps/installer/unpack.py
index 01a0144229..99e3fedfd3 100644
--- a/toolkit/mozapps/installer/unpack.py
+++ b/toolkit/mozapps/installer/unpack.py
@@ -10,8 +10,8 @@ import buildconfig
 
 def main():
     if len(sys.argv) != 2:
-        print >>sys.stderr, "Usage: %s directory" % \
-                            os.path.basename(sys.argv[0])
+        print("Usage: %s directory" % \
+                            os.path.basename(sys.argv[0]), file=sys.stderr)
         sys.exit(1)
 
     buildconfig.substs['USE_ELF_HACK'] = False
diff --git a/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py b/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py
index cb7303a129..8690d784dc 100644
--- a/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py
+++ b/toolkit/mozapps/installer/windows/nsis/preprocess-locale.py
@@ -37,7 +37,7 @@ def get_locale_strings(path, prefix, middle, add_cr):
              linefeeds when there isn't one already
     """
     output = ""
-    fp = open(path, "r")
+    fp = open(path)
     for line in fp:
         line = line.strip()
         if line == "" or line[0] == "#":
@@ -84,12 +84,12 @@ def preprocess_locale_files(config_dir, l10ndirs):
                                         "LangString ^",
                                         " 0 ",
                                         False)
-    fp.write(unicode(locale_strings, "utf-8").encode("utf-16-le"))
+    fp.write(str(locale_strings, "utf-8").encode("utf-16-le"))
     fp.close()
 
     # Create the Modern User Interface language file
     fp = open_utf16le_file(join(config_dir, "baseLocale.nsh"))
-    fp.write((u""";NSIS Modern User Interface - Language File
+    fp.write((""";NSIS Modern User Interface - Language File
 ;Compatible with Modern UI 1.68
 ;Language: baseLocale (0)
 !insertmacro MOZ_MUI_LANGUAGEFILE_BEGIN \"baseLocale\"
@@ -97,8 +97,8 @@ def preprocess_locale_files(config_dir, l10ndirs):
 """).encode("utf-16-le"))
     locale_strings = get_locale_strings(lookup("mui.properties", l10ndirs),
                                         "!define ", " ", True)
-    fp.write(unicode(locale_strings, "utf-8").encode("utf-16-le"))
-    fp.write(u"!insertmacro MOZ_MUI_LANGUAGEFILE_END\n".encode("utf-16-le"))
+    fp.write(str(locale_strings, "utf-8").encode("utf-16-le"))
+    fp.write("!insertmacro MOZ_MUI_LANGUAGEFILE_END\n".encode("utf-16-le"))
     fp.close()
 
     # Create the custom language file for our custom strings
@@ -108,7 +108,7 @@ def preprocess_locale_files(config_dir, l10ndirs):
                                         "LangString ",
                                         " 0 ",
                                         True)
-    fp.write(unicode(locale_strings, "utf-8").encode("utf-16-le"))
+    fp.write(str(locale_strings, "utf-8").encode("utf-16-le"))
     fp.close()
 
 def create_nlf_file(moz_dir, ab_cd, config_dir):
@@ -124,8 +124,7 @@ def create_nlf_file(moz_dir, ab_cd, config_dir):
 
     # Check whether the locale is right to left from locales.nsi.
     fp = open(join(moz_dir,
-                   "toolkit/mozapps/installer/windows/nsis/locales.nsi"),
-              "r")
+                   "toolkit/mozapps/installer/windows/nsis/locales.nsi"))
     for line in fp:
         line = line.strip()
         if line == "!define " + ab_cd + "_rtl":
@@ -138,7 +137,7 @@ def create_nlf_file(moz_dir, ab_cd, config_dir):
     # along with the default codepage, font name, and font size represented
     # by the '-' character.
     fp = open_utf16le_file(join(config_dir, "baseLocale.nlf"))
-    fp.write((u"""# Header, don't edit
+    fp.write(("""# Header, don't edit
 NLF v6
 # Start editing here
 # Language ID
@@ -175,7 +174,7 @@ def preprocess_locale_file(config_dir,
                                         "LangString ",
                                         " 0 ",
                                         True)
-    fp.write(unicode(locale_strings, "utf-8").encode("utf-16-le"))
+    fp.write(str(locale_strings, "utf-8").encode("utf-16-le"))
     fp.close()
 
 
@@ -187,9 +186,9 @@ def convert_utf8_utf16le(in_file_path, out_file_path):
     in_file_path  - the path to the UTF-8 source file to convert
     out_file_path - the path to the UTF-16LE destination file to create
     """
-    in_fp = open(in_file_path, "r")
+    in_fp = open(in_file_path)
     out_fp = open_utf16le_file(out_file_path)
-    out_fp.write(unicode(in_fp.read(), "utf-8").encode("utf-16-le"))
+    out_fp.write(str(in_fp.read(), "utf-8").encode("utf-16-le"))
     in_fp.close()
     out_fp.close()
 
diff --git a/toolkit/mozapps/update/updater/gen_cert_header.py b/toolkit/mozapps/update/updater/gen_cert_header.py
index 7ecb156197..2db776bb7d 100644
--- a/toolkit/mozapps/update/updater/gen_cert_header.py
+++ b/toolkit/mozapps/update/updater/gen_cert_header.py
@@ -1,5 +1,3 @@
-from __future__ import print_function
-
 import binascii
 
 def file_byte_generator(filename, block_size = 512):
@@ -7,8 +5,7 @@ def file_byte_generator(filename, block_size = 512):
     while True:
       block = f.read(block_size)
       if block:
-        for byte in block:
-          yield byte
+        yield from block
       else:
         break
 
diff --git a/tools/check-moz-style/checkmozstyle.py b/tools/check-moz-style/checkmozstyle.py
index d8261aec5a..6e45192432 100755
--- a/tools/check-moz-style/checkmozstyle.py
+++ b/tools/check-moz-style/checkmozstyle.py
@@ -116,7 +116,7 @@ def process_patch(patch_string, root, cwd, scm):
         cpplint.error("patch", 0, "patch/nodescription", 3,
                       "Patch does not have a description.")
 
-    for filename, diff in patch.files.iteritems():
+    for filename, diff in patch.files.items():
         file_extension = os.path.splitext(filename)[1]
 
         if file_extension in ['.cpp', '.c', '.h']:
diff --git a/tools/check-moz-style/modules/cpplint.py b/tools/check-moz-style/modules/cpplint.py
index c01e82d450..12f1edb9f9 100644
--- a/tools/check-moz-style/modules/cpplint.py
+++ b/tools/check-moz-style/modules/cpplint.py
@@ -851,7 +851,7 @@ def check_for_copyright(filename, lines, error):
 
     # We'll say it should occur by line 10. Don't forget there's a
     # dummy line at the front.
-    for line in xrange(1, min(len(lines), 11)):
+    for line in range(1, min(len(lines), 11)):
         if re.search(r'Copyright|License', lines[line], re.I):
             break
     else:                       # means no copyright line was found
@@ -1391,7 +1391,7 @@ def check_for_function_lengths(filename, clean_lines, line_number,
 
     if starting_func:
         body_found = False
-        for start_line_number in xrange(line_number, clean_lines.num_lines()):
+        for start_line_number in range(line_number, clean_lines.num_lines()):
             start_line = lines[start_line_number]
             joined_line += ' ' + start_line.lstrip()
             if search(r'(;|})', start_line):  # Declarations and trivial functions
@@ -2085,7 +2085,7 @@ def get_line_width(line):
       The width of the line in column positions, accounting for Unicode
       combining characters and wide characters.
     """
-    if isinstance(line, unicode):
+    if isinstance(line, str):
         width = 0
         for c in unicodedata.normalize('NFC', line):
             if unicodedata.east_asian_width(c) in ('W', 'F'):
@@ -2809,7 +2809,7 @@ def check_for_include_what_you_use(filename, clean_lines, include_state, error,
     required = {}  # A map of header name to line_number and the template entity.
         # Example of required: { '<functional>': (1219, 'less<>') }
 
-    for line_number in xrange(clean_lines.num_lines()):
+    for line_number in range(clean_lines.num_lines()):
         line = clean_lines.elided[line_number]
         if not line or line[0] == '#':
             continue
@@ -2938,7 +2938,7 @@ def process_file_data(filename, file_extension, lines, error):
 
     remove_multi_line_comments(filename, lines, error)
     clean_lines = CleansedLines(lines)
-    for line in xrange(clean_lines.num_lines()):
+    for line in range(clean_lines.num_lines()):
         process_line(filename, file_extension, clean_lines, line,
                      include_state, function_state, class_state, error)
     class_state.check_finished(filename, error)
diff --git a/tools/check-moz-style/modules/logging.py b/tools/check-moz-style/modules/logging.py
index ea03a489c6..42d7148bbf 100644
--- a/tools/check-moz-style/modules/logging.py
+++ b/tools/check-moz-style/modules/logging.py
@@ -29,10 +29,11 @@
 #
 # WebKit's Python module for logging
 
+from __future__ import print_function
 import sys
 
 def log(string):
-    print >> sys.stderr, string
+    print(string, file=sys.stderr)
 
 def error(string):
     log("ERROR: " + string)
diff --git a/tools/check-moz-style/modules/scm.py b/tools/check-moz-style/modules/scm.py
index e7cb9ffc60..07b9aa3ddd 100644
--- a/tools/check-moz-style/modules/scm.py
+++ b/tools/check-moz-style/modules/scm.py
@@ -29,6 +29,7 @@
 #
 # Python module for interacting with an SCM system (like SVN or Git)
 
+from __future__ import print_function
 import os
 import re
 import subprocess
@@ -118,7 +119,7 @@ class SCM:
 
     def ensure_clean_working_directory(self, force):
         if not force and not self.working_directory_is_clean():
-            print self.run_command(self.status_command(), raise_on_failure=False)
+            print(self.run_command(self.status_command(), raise_on_failure=False))
             error("Working directory has modifications, pass --force-clean or --no-clean to continue.")
         
         log("Cleaning working directory")
@@ -157,45 +158,45 @@ class SCM:
 
     @staticmethod
     def in_working_directory(path):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     @staticmethod
     def find_checkout_root(path):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     @staticmethod
     def commit_success_regexp():
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def working_directory_is_clean(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def clean_working_directory(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def update_webkit(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def status_command(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def changed_files(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def display_name(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def create_patch(self):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def commit_with_message(self, message):
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
     
     # Subclasses must indicate if they support local commits,
     # but the SCM baseclass will only call local_commits methods when this is true.
     @staticmethod
     def supports_local_commits():
-        raise NotImplementedError, "subclasses must implement"
+        raise NotImplementedError("subclasses must implement")
 
     def create_patch_from_local_commit(self, commit_id):
         pass
diff --git a/tools/lint/eslint.lint b/tools/lint/eslint.lint
index a2d864f75f..9b14160403 100644
--- a/tools/lint/eslint.lint
+++ b/tools/lint/eslint.lint
@@ -10,8 +10,31 @@ import re
 import signal
 import subprocess
 import sys
-from distutils.version import LooseVersion
-
+try:
+    from distutils.version import LooseVersion
+except ImportError:
+    import re as _re
+    class LooseVersion:
+        def __init__(self, vstring):
+            self.vstring = vstring
+            self.version = [int(x) if x.isdigit() else x for x in _re.split(r'[.\-]', vstring)]
+        def __str__(self): return self.vstring
+        def __repr__(self): return "LooseVersion ('%s')" % str(self)
+        def _cmp(self, other):
+            if not isinstance(other, LooseVersion): other = LooseVersion(other)
+            a, b = self.version, other.version
+            for i in range(max(len(a), len(b))):
+                va = a[i] if i < len(a) else 0
+                vb = b[i] if i < len(b) else 0
+                if type(va) != type(vb): va, vb = str(va), str(vb)
+                if va < vb: return -1
+                if va > vb: return 1
+            return 0
+        def __eq__(self, other): return self._cmp(other) == 0
+        def __lt__(self, other): return self._cmp(other) < 0
+        def __le__(self, other): return self._cmp(other) <= 0
+        def __gt__(self, other): return self._cmp(other) > 0
+        def __ge__(self, other): return self._cmp(other) >= 0
 import which
 from mozprocess import ProcessHandler
 
diff --git a/tools/mach_commands.py b/tools/mach_commands.py
index 898073bb63..1c67fa68bb 100644
--- a/tools/mach_commands.py
+++ b/tools/mach_commands.py
@@ -4,6 +4,7 @@
 
 from __future__ import absolute_import, unicode_literals
 
+from __future__ import print_function
 import sys
 import os
 import stat
@@ -75,9 +76,9 @@ class UUIDProvider(object):
                 print('')
         if format in [None, 'cpp', 'c++']:
             u = u.hex
-            print('{ 0x%s, 0x%s, 0x%s, \\' % (u[0:8], u[8:12], u[12:16]))
-            pairs = tuple(map(lambda n: u[n:n+2], range(16, 32, 2)))
-            print(('  { ' + '0x%s, ' * 7 + '0x%s } }') % pairs)
+            print(('{ 0x%s, 0x%s, 0x%s, \\' % (u[0:8], u[8:12], u[12:16])))
+            pairs = tuple([u[n:n+2] for n in range(16, 32, 2)])
+            print((('  { ' + '0x%s, ' * 7 + '0x%s } }') % pairs))
 
 
 @CommandProvider
@@ -92,7 +93,7 @@ class RageProvider(MachCommandBase):
         form where you can submit feedback. Just close the tab when done.
         """
         import getpass
-        import urllib
+        import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
         import webbrowser
 
         # Try to resolve the current user.
@@ -127,7 +128,7 @@ class RageProvider(MachCommandBase):
 
         url = 'https://docs.google.com/a/mozilla.com/forms/d/e/1FAIpQLSeDVC3IXJu5d33Hp_ZTCOw06xEUiYH1pBjAqJ1g_y63sO2vvA/viewform'
         if user:
-            url += '?entry.1281044204=%s' % urllib.quote(user)
+            url += '?entry.1281044204=%s' % six.moves.urllib.parse.quote(user)
 
         print('Please leave your feedback in the opened web form')
         webbrowser.open_new_tab(url)
@@ -148,8 +149,8 @@ class PastebinProvider(object):
                      help='Specify the file to upload to pastebin.mozilla.org')
 
     def pastebin(self, language, poster, duration, file):
-        import urllib
-        import urllib2
+        import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
+        import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
         URL = 'https://pastebin.mozilla.org/'
 
@@ -183,7 +184,7 @@ class PastebinProvider(object):
                 extension = file.split('.')[-1]
                 for l in FILE_TYPES:
                     if extension == l['extension']:
-                        print('Identified file as %s' % l['name'])
+                        print(('Identified file as %s' % l['name']))
                         lang = l['value']
             except IOError:
                 print('ERROR. No such file')
@@ -204,18 +205,18 @@ class PastebinProvider(object):
             ('expiry', duration),
             ('paste', 'Send')]
 
-        data = urllib.urlencode(params)
+        data = six.moves.urllib.parse.urlencode(params)
         print('Uploading ...')
         try:
-            req = urllib2.Request(URL, data)
-            response = urllib2.urlopen(req)
+            req = six.moves.urllib.request.Request(URL, data)
+            response = six.moves.urllib.request.urlopen(req)
             http_response_code = response.getcode()
             if http_response_code == 200:
-                print(response.geturl())
+                print((response.geturl()))
             else:
-                print('Could not upload the file, '
-                      'HTTP Response Code %s' %(http_response_code))
-        except urllib2.URLError:
+                print(('Could not upload the file, '
+                      'HTTP Response Code %s' %(http_response_code)))
+        except six.moves.urllib.error.URLError:
             print('ERROR. Could not connect to pastebin.mozilla.org.')
             return 1
         return 0
@@ -228,7 +229,7 @@ class FormatProvider(MachCommandBase):
     @CommandArgument('--show', '-s', action = 'store_true',
         help = 'Show diff output on instead of applying changes')
     def clang_format(self, show=False):
-        import urllib2
+        import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse
 
         plat = platform.system()
         fmt = plat.lower() + "/clang-format-3.5"
@@ -242,8 +243,8 @@ class FormatProvider(MachCommandBase):
         else:
             arch = os.uname()[4]
             if (plat != "Linux" and plat != "Darwin") or arch != 'x86_64':
-                print("Unsupported platform " + plat + "/" + arch +
-                      ". Supported platforms are Windows/*, Linux/x86_64 and Darwin/x86_64")
+                print(("Unsupported platform " + plat + "/" + arch +
+                      ". Supported platforms are Windows/*, Linux/x86_64 and Darwin/x86_64"))
                 return 1
 
         os.chdir(self.topsrcdir)
@@ -256,8 +257,8 @@ class FormatProvider(MachCommandBase):
             if not clang_format_diff:
                 return 1
 
-        except urllib2.HTTPError as e:
-            print("HTTP error {0}: {1}".format(e.code, e.reason))
+        except six.moves.urllib.error.HTTPError as e:
+            print(("HTTP error {0}: {1}".format(e.code, e.reason)))
             return 1
 
         from subprocess import Popen, PIPE
@@ -276,7 +277,7 @@ class FormatProvider(MachCommandBase):
                 if e.errno == errno.ENOENT:
                     print("Can't find filterdiff. Please install patchutils.")
                 else:
-                    print("OSError {0}: {1}".format(e.code, e.reason))
+                    print(("OSError {0}: {1}".format(e.code, e.reason)))
                 return 1
 
 
@@ -290,14 +291,14 @@ class FormatProvider(MachCommandBase):
         target = os.path.join(self._mach_context.state_dir, os.path.basename(root))
         if not os.path.exists(target):
             site = "https://people.mozilla.org/~ajones/clang-format/"
-            if self.prompt and raw_input("Download clang-format executables from {0} (yN)? ".format(site)).lower() != 'y':
+            if self.prompt and input("Download clang-format executables from {0} (yN)? ".format(site)).lower() != 'y':
                 print("Download aborted.")
                 return 1
             self.prompt = False
 
             u = site + root
-            print("Downloading {0} to {1}".format(u, target))
-            data = urllib2.urlopen(url=u).read()
+            print(("Downloading {0} to {1}".format(u, target)))
+            data = six.moves.urllib.request.urlopen(url=u).read()
             temp = target + ".tmp"
             with open(temp, "wb") as fh:
                 fh.write(data)
@@ -340,8 +341,8 @@ def mozregression_create_parser():
                 'install',
                 'mozregression==%s' % release
             ])
-            print("mozregression was updated to version %s. please"
-                  " re-run your command." % release)
+            print(("mozregression was updated to version %s. please"
+                  " re-run your command." % release))
         else:
             # mozregression is up to date, return the parser.
             return mozregression.parser()
diff --git a/tools/power/mach_commands.py b/tools/power/mach_commands.py
index 281e7a868e..587e717a39 100644
--- a/tools/power/mach_commands.py
+++ b/tools/power/mach_commands.py
@@ -4,7 +4,7 @@
 
 from __future__ import print_function
 
-from distutils.version import StrictVersion
+# StrictVersion replaced
 
 from mach.decorators import (
     Command,
diff --git a/tools/profiler/merge-profiles.py b/tools/profiler/merge-profiles.py
index 0c10c60e1d..5037030841 100755
--- a/tools/profiler/merge-profiles.py
+++ b/tools/profiler/merge-profiles.py
@@ -5,6 +5,7 @@
 # is used to syncronized the samples. Each thread is moved into the merged
 # profile.
 #
+from __future__ import print_function
 import json
 import re
 import sys
@@ -107,7 +108,7 @@ if len(sys.argv) > 1:
     MergeProfiles(sys.argv[1:])
     sys.exit(0)
 
-print "Usage: merge-profile.py profile_<pid1>_<pname1>.sym profile_<pid2>_<pname2>.sym > merged.sym"
+print("Usage: merge-profile.py profile_<pid1>_<pname1>.sym profile_<pid2>_<pname2>.sym > merged.sym")
 
 
 
diff --git a/tools/profiler/nm-symbolicate.py b/tools/profiler/nm-symbolicate.py
index f51d7f75f5..9b380ad9df 100755
--- a/tools/profiler/nm-symbolicate.py
+++ b/tools/profiler/nm-symbolicate.py
@@ -4,6 +4,7 @@
 # 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 print_function
 import sys, subprocess, os
 
 def NMSymbolicate(library, addresses):
@@ -34,15 +35,15 @@ def NMSymbolicate(library, addresses):
         symbolForAddress = symbol
         break
     if symbolForAddress:
-      print symbolForAddress["funcName"]
+      print(symbolForAddress["funcName"])
     else:
-      print "??" # match addr2line
-    print ":0" # no line information from nm
+      print("??") # match addr2line
+    print(":0") # no line information from nm
 
 if len(sys.argv) > 1:
     NMSymbolicate(sys.argv[1], sys.argv[2:])
     sys.exit(0)
 
-print "Usage: nm-symbolicate.py <library> <addresses> > merged.sym"
+print("Usage: nm-symbolicate.py <library> <addresses> > merged.sym")
 
 
diff --git a/tools/rb/find_leakers.py b/tools/rb/find_leakers.py
index 4405d7a179..3f32f7d4b6 100755
--- a/tools/rb/find_leakers.py
+++ b/tools/rb/find_leakers.py
@@ -10,21 +10,22 @@
 # Please see README file in the same directory.
 
 
+from __future__ import print_function
 import sys
 
 def print_output(allocation, obj_to_class):
     '''Formats and prints output.'''
     items = []
-    for obj, count, in allocation.iteritems():
+    for obj, count, in allocation.items():
         # Adding items to a list, so we can sort them.
         items.append((obj, count))
     # Sorting by count.
     items.sort(key=lambda item: item[1])
 
     for obj, count, in items:
-        print "{obj} ({count}) @ {class_name}".format(obj=obj,
+        print("{obj} ({count}) @ {class_name}".format(obj=obj,
                                                       count=count,
-                                                      class_name=obj_to_class[obj])
+                                                      class_name=obj_to_class[obj]))
 
 def process_log(log_lines):
     '''Process through the log lines, and print out the result.
@@ -63,8 +64,8 @@ def process_log(log_lines):
             #     <nsStringBuffer> 0x01AFD3B8 1 Release 0
             #     <PStreamNotifyParent> 0x08880BD0 8 Dtor (20)
             if obj not in allocation:
-                print "An object was released that wasn't allocated!",
-                print obj, "@", class_name
+                print("An object was released that wasn't allocated!", end=' ')
+                print(obj, "@", class_name)
             else:
                 allocation.pop(obj)
             obj_to_class.pop(obj)
@@ -74,12 +75,12 @@ def process_log(log_lines):
 
 
 def print_usage():
-    print
-    print "Usage: find-leakers.py [log-file]"
-    print
-    print "If `log-file' provided, it will read that as the input log."
-    print "Else, it will read the stdin as the input log."
-    print
+    print()
+    print("Usage: find-leakers.py [log-file]")
+    print()
+    print("If `log-file' provided, it will read that as the input log.")
+    print("Else, it will read the stdin as the input log.")
+    print()
 
 def main():
     '''Main method of the script.'''
@@ -92,7 +93,7 @@ def main():
             log_lines = log_file.readlines()
         process_log(log_lines)
     else:
-        print 'ERROR: Invalid number of arguments'
+        print('ERROR: Invalid number of arguments')
         print_usage()
 
 if __name__ == '__main__':
diff --git a/tools/rb/fix_linux_stack.py b/tools/rb/fix_linux_stack.py
index 146e6eebdf..64a0ca76ae 100755
--- a/tools/rb/fix_linux_stack.py
+++ b/tools/rb/fix_linux_stack.py
@@ -7,6 +7,7 @@
 # produced by NS_FormatCodeAddress(), which on Linux often lack a function
 # name, a file name and a line number.
 
+from __future__ import print_function
 import subprocess
 import sys
 import re
@@ -40,7 +41,7 @@ class unbufferedLineConverter:
     def test():
         assert unbufferedLineConverter("rev").convert("123") == "321"
         assert unbufferedLineConverter("cut", ["-c3"]).convert("abcde") == "c"
-        print "Pass"
+        print("Pass")
 
 objdump_section_re = re.compile("^ [0-9a-f]* ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}) ([0-9a-f ]{8}).*")
 def elf_section(file, section):
@@ -173,11 +174,11 @@ def separate_debug_file_for(file):
 
     def word32(s):
         if type(s) != str or len(s) != 4:
-            raise StandardError("expected 4 byte string input")
+            raise Exception("expected 4 byte string input")
         s = list(s)
         if endian == "big":
             s.reverse()
-        return sum(map(lambda idx: ord(s[idx]) * (256 ** idx), range(0, 4)))
+        return sum([ord(s[idx]) * (256 ** idx) for idx in range(0, 4)])
 
     buildid = elf_section(file, ".note.gnu.build-id");
     if buildid is not None:
@@ -192,7 +193,7 @@ def separate_debug_file_for(file):
            note_header[12:16] != "GNU\0":
             sys.stderr.write("malformed .note.gnu.build_id in " + file + "\n")
         else:
-            buildid = "".join(map(lambda ch: "%02X" % ord(ch), buildid)).lower()
+            buildid = "".join(["%02X" % ord(ch) for ch in buildid]).lower()
             f = os.path.join(global_debug_dir, ".build-id", buildid[0:2], buildid[2:] + ".debug")
             if have_debug_file(f):
                 return f
diff --git a/tools/rb/fix_macosx_stack.py b/tools/rb/fix_macosx_stack.py
index 32831e9134..e1b63a8675 100755
--- a/tools/rb/fix_macosx_stack.py
+++ b/tools/rb/fix_macosx_stack.py
@@ -7,6 +7,7 @@
 # NS_FormatCodeAddress(), which on Mac often lack a file name and a line
 # number.
 
+from __future__ import print_function
 import subprocess
 import sys
 import re
@@ -39,7 +40,7 @@ class unbufferedLineConverter:
     def test():
         assert unbufferedLineConverter("rev").convert("123") == "321"
         assert unbufferedLineConverter("cut", ["-c3"]).convert("abcde") == "c"
-        print "Pass"
+        print("Pass")
 
 def separate_debug_file_for(file):
     return None
@@ -56,13 +57,13 @@ def address_adjustment(file):
             if line == "  segname __TEXT\n":
                 line = otool.stdout.readline()
                 if not line.startswith("   vmaddr "):
-                    raise StandardError("unexpected otool output")
+                    raise Exception("unexpected otool output")
                 result = int(line[10:], 16)
                 break
         otool.stdout.close()
 
         if result is None:
-            raise StandardError("unexpected otool output")
+            raise Exception("unexpected otool output")
 
         address_adjustments[file] = result
 
diff --git a/tools/rb/fix_stack_using_bpsyms.py b/tools/rb/fix_stack_using_bpsyms.py
index 5d04cd02a1..798aaf8fc7 100755
--- a/tools/rb/fix_stack_using_bpsyms.py
+++ b/tools/rb/fix_stack_using_bpsyms.py
@@ -10,6 +10,7 @@
 
 from __future__ import with_statement
 
+from __future__ import print_function
 import sys
 import os
 import re
@@ -160,4 +161,4 @@ def fixSymbols(line, symbolsDir):
 if __name__ == "__main__":
   symbolsDir = sys.argv[1]
   for line in iter(sys.stdin.readline, ''):
-    print fixSymbols(line, symbolsDir),
+    print(fixSymbols(line, symbolsDir), end=' ')
diff --git a/tools/update-packaging/generatesnippet.py b/tools/update-packaging/generatesnippet.py
index 15b7edf588..8fb2abbe44 100644
--- a/tools/update-packaging/generatesnippet.py
+++ b/tools/update-packaging/generatesnippet.py
@@ -7,9 +7,10 @@ This script generates the complete snippet for a given locale or en-US
 Most of the parameters received are to generate the MAR's download URL
 and determine the MAR's filename
 """
+from __future__ import print_function
 import sys, os, platform, sha
 from optparse import OptionParser
-from ConfigParser import ConfigParser
+from configparser import ConfigParser
 from stat import ST_SIZE
 
 def main():
@@ -80,7 +81,7 @@ def main():
 
     if options.verbose:
         # Show in our logs what the contents of the snippet are
-        print snippet
+        print(snippet)
 
 def generateSnippet(abstDistDir, applicationIniFile, locale,
                     downloadBaseURL, product, platform, branch):
@@ -88,7 +89,8 @@ def generateSnippet(abstDistDir, applicationIniFile, locale,
     c = ConfigParser()
     try:
         c.readfp(open(applicationIniFile))
-    except IOError, (stderror):
+    except IOError as xxx_todo_changeme:
+       (stderror) = xxx_todo_changeme
        sys.exit(stderror)
     buildid = c.get("App", "BuildID")
     appVersion = c.get("App", "Version")
@@ -141,7 +143,8 @@ def getFileHashAndSize(filepath):
         shaObj = sha.new(f.read())
         sha1Hash = shaObj.hexdigest()
         size = os.stat(filepath)[ST_SIZE]
-    except IOError, (stderror):
+    except IOError as xxx_todo_changeme1:
+       (stderror) = xxx_todo_changeme1
        sys.exit(stderror)
 
     return (sha1Hash, size)
diff --git a/tools/update-packaging/make_incremental_updates.py b/tools/update-packaging/make_incremental_updates.py
index dc7b3a01ea..07cfe5bcb6 100755
--- a/tools/update-packaging/make_incremental_updates.py
+++ b/tools/update-packaging/make_incremental_updates.py
@@ -2,6 +2,7 @@
 # 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 print_function
 import os
 import shutil
 import hashlib
@@ -46,11 +47,11 @@ class PatchInfo:
         if m:
             # Directory immediately following extensions is used for the test
             testdir = m.group(1)
-            print '     add-if "'+testdir+'" "'+filename+'"'
+            print('     add-if "'+testdir+'" "'+filename+'"')
             self.manifestv2.append('add-if "'+testdir+'" "'+filename+'"')
             self.manifestv3.append('add-if "'+testdir+'" "'+filename+'"')
         else:
-            print '        add "'+filename+'"'
+            print('        add "'+filename+'"')
             self.manifestv2.append('add "'+filename+'"')
             self.manifestv3.append('add "'+filename+'"')
 
@@ -59,7 +60,7 @@ class PatchInfo:
             This was ported from mozilla/tools/update-packaging/common.sh's
             make_add_if_not_instruction.
         """
-        print ' add-if-not "'+filename+'" "'+filename+'"'
+        print(' add-if-not "'+filename+'" "'+filename+'"')
         self.manifestv3.append('add-if-not "'+filename+'" "'+filename+'"')
 
     def append_patch_instruction(self, filename, patchname):
@@ -76,11 +77,11 @@ class PatchInfo:
         m = re.match("((?:|.*/)distribution/extensions/.*)/", filename)
         if m:
             testdir = m.group(1)
-            print '   patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"'
+            print('   patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"')
             self.manifestv2.append('patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"')
             self.manifestv3.append('patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"')
         else:
-            print '      patch "'+patchname+'" "'+filename+'"'
+            print('      patch "'+patchname+'" "'+filename+'"')
             self.manifestv2.append('patch "'+patchname+'" "'+filename+'"')
             self.manifestv3.append('patch "'+patchname+'" "'+filename+'"')
 
@@ -90,16 +91,16 @@ class PatchInfo:
             mozilla/tools/update-packaging/common.sh/make_remove_instruction
         """
         if filename.endswith("/"):
-            print '      rmdir "'+filename+'"'
+            print('      rmdir "'+filename+'"')
             self.manifestv2.append('rmdir "'+filename+'"')
             self.manifestv3.append('rmdir "'+filename+'"')
         elif filename.endswith("/*"):
             filename = filename[:-1]
-            print '    rmrfdir "'+filename+'"'
+            print('    rmrfdir "'+filename+'"')
             self.manifestv2.append('rmrfdir "'+filename+'"')
             self.manifestv3.append('rmrfdir "'+filename+'"')
         else:
-            print '     remove "'+filename+'"'
+            print('     remove "'+filename+'"')
             self.manifestv2.append('remove "'+filename+'"')
             self.manifestv3.append('remove "'+filename+'"')
 
@@ -217,7 +218,7 @@ def xzunzip_file(filename):
 def extract_mar(filename, work_dir):
     """ Extracts the marfile intot he work_dir
         assumes work_dir already exists otherwise will throw osError"""
-    print "Extracting "+filename+" to "+work_dir
+    print("Extracting "+filename+" to "+work_dir)
     saved_path = os.getcwd()
     try:
         os.chdir(work_dir)
@@ -229,7 +230,7 @@ def create_partial_patch_for_file(from_marfile_entry, to_marfile_entry, shas, pa
     """ Creates the partial patch file and manifest entry for the pair of files passed in
     """
     if not (from_marfile_entry.sha(),to_marfile_entry.sha()) in shas:
-        print 'diffing "'+from_marfile_entry.name+'\"'
+        print('diffing "'+from_marfile_entry.name+'\"')
         #bunzip to/from
         bunzip_file(from_marfile_entry.abs_path)
         bunzip_file(to_marfile_entry.abs_path)
@@ -343,7 +344,7 @@ def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch
     elif "Contents\Resources\precomplete" in to_file_set:
         forced_list.append("Contents\Resources\precomplete")
     else:
-        raise Exception, "missing precomplete file in: "+to_dir_path
+        raise Exception("missing precomplete file in: "+to_dir_path)
 
     if "removed-files" in to_file_set:
         forced_list.append("removed-files")
@@ -353,7 +354,7 @@ def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch
     elif "Contents\Resources\\removed-files" in to_file_set:
         forced_list.append("Contents\Resources\\removed-files")
     else:
-        raise Exception, "missing removed-files file in: "+to_dir_path
+        raise Exception("missing removed-files file in: "+to_dir_path)
 
     if "chrome.manifest" in to_file_set:
         forced_list.append("chrome.manifest")
@@ -363,7 +364,7 @@ def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch
     elif "Contents\Resources\\chrome.manifest" in to_file_set:
         forced_list.append("Contents\Resources\\chrome.manifest")
     else:
-        raise Exception, "missing chrome.manifest file in: "+to_dir_path
+        raise Exception("missing chrome.manifest file in: "+to_dir_path)
 
     # Files which exist in both sets need to be patched
     patch_filenames = list(from_file_set.intersection(to_file_set))
@@ -375,7 +376,7 @@ def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch
             # This filename is in the add if not list, explicitly add-if-not
             create_add_if_not_patch_for_file(to_dir_hash[filename], patch_info)
         elif filename in forced_list:
-            print 'Forcing "'+filename+'"'
+            print('Forcing "'+filename+'"')
             # This filename is in the forced list, explicitly add
             create_add_patch_for_file(to_dir_hash[filename], patch_info)
         else:
@@ -422,8 +423,8 @@ def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch
     return patch_filename
 
 def usage():
-    print "-h for help"
-    print "-f for patchlist_file"
+    print("-h for help")
+    print("-f for patchlist_file")
 
 def get_buildid(work_dir):
     """ extracts buildid from MAR
@@ -432,7 +433,7 @@ def get_buildid(work_dir):
     if not os.path.exists(ini):
         ini = '%s/Contents/Resources/application.ini' % work_dir
         if not os.path.exists(ini):
-            print 'WARNING: application.ini not found, cannot find build ID'
+            print('WARNING: application.ini not found, cannot find build ID')
             return ''
 
     fd, tmppath = tempfile.mkstemp('', 'tmp', os.getcwd())
@@ -460,7 +461,7 @@ def decode_filename(filepath):
         '(?P<product>\w+)(-)(?P<version>\w+\.\w+(\.\w+){0,2})(\.)(?P<locale>.+?)(\.)(?P<platform>.+?)(\.)(?P<type>\w+)(.mar)',
       os.path.basename(filepath))
       return m.groupdict()
-    except Exception, exc:
+    except Exception as exc:
       try:
         m = re.search(
           '(?P<platform>.+?)\/(?P<locale>.+?)\/(?P<product>\w+)-(?P<version>\w+\.\w+)\.(?P<type>\w+).mar',
@@ -477,7 +478,7 @@ def create_partial_patches(patches):
     metadata = []
     try:
         work_dir_root = tempfile.mkdtemp('-fastmode', 'tmp', os.getcwd())
-        print "Building patches using work dir: %s" % (work_dir_root)
+        print("Building patches using work dir: %s" % (work_dir_root))
 
         # Iterate through every patch set in the patch file
         patch_num = 1
@@ -533,7 +534,7 @@ def create_partial_patches(patches):
              'locale':from_decoded['locale'],
              'platform':from_decoded['platform'],
             })
-            print "done with patch %s/%s time (%.2fs/%.2fs/%.2fs) (mar/patch/total)" % (str(patch_num),str(len(patches)),mar_extract_time-startTime,time.time()-mar_extract_time,time.time()-startTime)
+            print("done with patch %s/%s time (%.2fs/%.2fs/%.2fs) (mar/patch/total)" % (str(patch_num),str(len(patches)),mar_extract_time-startTime,time.time()-mar_extract_time,time.time()-startTime))
             patch_num += 1
         return metadata
     finally:
diff --git a/xpcom/idl-parser/xpidl/header.py b/xpcom/idl-parser/xpidl/header.py
index 8e854c4da8..9e5fe08e31 100644
--- a/xpcom/idl-parser/xpidl/header.py
+++ b/xpcom/idl-parser/xpidl/header.py
@@ -10,7 +10,7 @@
 import sys
 import os.path
 import re
-import xpidl
+from . import xpidl
 import itertools
 import glob
 
@@ -410,7 +410,7 @@ def write_interface(iface, fd):
 
     names = uuid_decoder.match(iface.attributes.uuid).groupdict()
     m3str = names['m3'] + names['m4']
-    names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in xrange(0, 16, 2)])
+    names['m3joined'] = ", ".join(["0x%s" % m3str[i:i+2] for i in range(0, 16, 2)])
 
     if iface.name[2] == 'I':
         implclass = iface.name[:2] + iface.name[3:]
diff --git a/xpcom/idl-parser/xpidl/runtests.py b/xpcom/idl-parser/xpidl/runtests.py
index 89222d5467..42d596766f 100644
--- a/xpcom/idl-parser/xpidl/runtests.py
+++ b/xpcom/idl-parser/xpidl/runtests.py
@@ -7,8 +7,8 @@
 
 import mozunit
 import unittest
-import xpidl
-import header
+from . import xpidl
+from . import header
 
 
 class TestParser(unittest.TestCase):
diff --git a/xpcom/idl-parser/xpidl/typelib.py b/xpcom/idl-parser/xpidl/typelib.py
index 911e3873da..79d2d30964 100644
--- a/xpcom/idl-parser/xpidl/typelib.py
+++ b/xpcom/idl-parser/xpidl/typelib.py
@@ -7,9 +7,10 @@
 
 """Generate an XPIDL typelib for the IDL files specified on the command line"""
 
+from __future__ import print_function
 import os
 import sys
-import xpidl
+from . import xpidl
 import xpt
 
 # A map of xpidl.py types to xpt.py types
@@ -274,14 +275,14 @@ if __name__ == '__main__':
 
     if options.regen:
         if options.cachedir is None:
-            print >>sys.stderr, "--regen requires --cachedir"
+            print("--regen requires --cachedir", file=sys.stderr)
             sys.exit(1)
 
         p = xpidl.IDLParser(outputdir=options.cachedir, regen=True)
         sys.exit(0)
 
     if options.depfile is not None and options.outfile is None:
-        print >>sys.stderr, "-d requires -o"
+        print("-d requires -o", file=sys.stderr)
         sys.exit(1)
 
     if options.outfile is not None:
@@ -302,6 +303,6 @@ if __name__ == '__main__':
         depfd = open(options.depfile, 'w')
         deps = [dep.replace('\\', '/') for dep in idl.deps]
 
-        print >>depfd, "%s: %s" % (options.outfile, " ".join(deps))
+        print("%s: %s" % (options.outfile, " ".join(deps)), file=depfd)
         for dep in deps:
-            print >>depfd, "%s:" % dep
+            print("%s:" % dep, file=depfd)
diff --git a/xpcom/idl-parser/xpidl/xpidl.py b/xpcom/idl-parser/xpidl/xpidl.py
index 6bb1ad5de5..99e508fbb6 100755
--- a/xpcom/idl-parser/xpidl/xpidl.py
+++ b/xpcom/idl-parser/xpidl/xpidl.py
@@ -7,6 +7,7 @@
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
+from __future__ import print_function
 import sys
 import os.path
 import re
@@ -36,7 +37,7 @@ def attlistToIDL(attlist):
         return ''
 
     attlist = list(attlist)
-    attlist.sort(cmp=lambda a, b: cmp(a[0], b[0]))
+    attlist.sort(key=lambda a: a[0])
 
     return '[%s] ' % ','.join(["%s%s" % (name, value is not None and '(%s)' % value or '')
                               for name, value, aloc in attlist])
@@ -113,7 +114,7 @@ class Builtin(object):
 
     def nativeType(self, calltype, shared=False, const=False):
         if const:
-            print >>sys.stderr, IDLError("[const] doesn't make sense on builtin types.", self.location, warning=True)
+            print(IDLError("[const] doesn't make sense on builtin types.", self.location, warning=True), file=sys.stderr)
             const = 'const '
         elif calltype == 'in' and self.nativename.endswith('*'):
             const = 'const '
@@ -173,7 +174,7 @@ class Location(object):
 
     def pointerline(self):
         def i():
-            for i in xrange(0, self._colno):
+            for i in range(0, self._colno):
                 yield " "
             yield "^"
 
@@ -201,7 +202,7 @@ class NameMap(object):
         return self._d[key]
 
     def __iter__(self):
-        return self._d.itervalues()
+        return iter(self._d.values())
 
     def __contains__(self, key):
         return key in builtinMap or key in self._d
@@ -374,10 +375,10 @@ class Forward(object):
         # Hack alert: if an identifier is already present, move the doccomments
         # forward.
         if parent.hasName(self.name):
-            for i in xrange(0, len(parent.productions)):
+            for i in range(0, len(parent.productions)):
                 if parent.productions[i] is self:
                     break
-            for i in xrange(i + 1, len(parent.productions)):
+            for i in range(i + 1, len(parent.productions)):
                 if hasattr(parent.productions[i], 'doccomments'):
                     parent.productions[i].doccomments[0:0] = self.doccomments
                     break
@@ -422,7 +423,7 @@ class Native(object):
                 if self.modifier is not None:
                     raise IDLError("More than one ptr/ref modifier", aloc)
                 self.modifier = name
-            elif name in self.specialtypes.keys():
+            elif name in list(self.specialtypes.keys()):
                 if self.specialtype is not None:
                     raise IDLError("More than one special type", aloc)
                 self.specialtype = name
@@ -516,7 +517,7 @@ class Interface(object):
         if self.attributes.function:
             has_method = False
             for member in self.members:
-                if member.kind is 'method':
+                if member.kind == 'method':
                     if has_method:
                         raise IDLError("interface '%s' has multiple methods, but marked 'function'" % self.name, self.location)
                     else:
@@ -1003,9 +1004,9 @@ class Param(object):
 
         try:
             return self.realtype.nativeType(self.paramtype, **kwargs)
-        except IDLError, e:
+        except IDLError as e:
             raise IDLError(e.message, self.location)
-        except TypeError, e:
+        except TypeError as e:
             raise IDLError("Unexpected parameter attribute", self.location)
 
     def toIDL(self):
@@ -1053,7 +1054,7 @@ class IDLParser(object):
         'NATIVEID',
         ]
 
-    tokens.extend(keywords.values())
+    tokens.extend(list(keywords.values()))
 
     states = (
         ('nativeid', 'exclusive'),
@@ -1071,13 +1072,13 @@ class IDLParser(object):
     t_ignore = ' \t'
 
     def t_multilinecomment(self, t):
-        r'/\*(?s).*?\*/'
+        r'/\*.*?\*/'
         t.lexer.lineno += t.value.count('\n')
         if t.value.startswith("/**"):
             self._doccomments.append(t.value)
 
     def t_singlelinecomment(self, t):
-        r'(?m)//.*?$'
+        r'//[^\n]*'
 
     def t_IID(self, t):
         return t
@@ -1089,7 +1090,7 @@ class IDLParser(object):
         return t
 
     def t_LCDATA(self, t):
-        r'(?s)%\{[ ]*C\+\+[ ]*\n(?P<cdata>.*?\n?)%\}[ ]*(C\+\+)?'
+        r'%\{[ ]*C\+\+[ ]*\n(?P<cdata>.*?\n?)%\}[ ]*(C\+\+)?'
         t.type = 'CDATA'
         t.value = t.lexer.lexmatch.group('cdata')
         t.lexer.lineno += t.value.count('\n')
@@ -1214,7 +1215,7 @@ class IDLParser(object):
 
     def p_interface(self, p):
         """interface : attributes INTERFACE IDENTIFIER ifacebase ifacebody ';'"""
-        atts, INTERFACE, name, base, body, SEMI = p[1:]
+        atts, INTERFACE, name, base, body, SEMI = p[1], p[2], p[3], p[4], p[5], p[6]
         attlist = atts['attlist']
         doccomments = []
         if 'doccomments' in atts:
@@ -1428,6 +1429,7 @@ class IDLParser(object):
         self.lexer = lex.lex(object=self,
                              outputdir=outputdir,
                              lextab='xpidllex',
+                             reflags=re.DOTALL,
                              optimize=1)
         self.parser = yacc.yacc(module=self,
                                 outputdir=outputdir,
@@ -1461,5 +1463,5 @@ class IDLParser(object):
 if __name__ == '__main__':
     p = IDLParser()
     for f in sys.argv[1:]:
-        print "Parsing %s" % f
+        print("Parsing %s" % f)
         p.parse(open(f).read(), filename=f)
diff --git a/xpcom/typelib/xpt/tools/runtests.py b/xpcom/typelib/xpt/tools/runtests.py
index a86e6625df..7dcb1f1a1f 100644
--- a/xpcom/typelib/xpt/tools/runtests.py
+++ b/xpcom/typelib/xpt/tools/runtests.py
@@ -30,6 +30,7 @@
 # official policies, either expressed or implied, of the Mozilla
 # Foundation.
 
+from __future__ import print_function
 import difflib
 import os
 from StringIO import StringIO
@@ -66,9 +67,9 @@ if "MOZILLA_OBJDIR" in os.environ:
                 # now run xpt_dump on it
                 out2 = get_output(xptdump, fullpath)
                 if out != out2:
-                    print "diff %s" % f
+                    print("diff %s" % f)
                     for line in difflib.unified_diff(out2.split("\n"), out.split("\n"), lineterm=""):
-                        print line
+                        print(line)
                 self.assert_(out == out2, "xpt_dump output should be identical for %s" % f)
 
 
diff --git a/xpcom/typelib/xpt/tools/xpt.py b/xpcom/typelib/xpt/tools/xpt.py
index 67d40f7b2d..99a5a566b3 100755
--- a/xpcom/typelib/xpt/tools/xpt.py
+++ b/xpcom/typelib/xpt/tools/xpt.py
@@ -66,13 +66,18 @@ InterfaceType()        - construct a new object representing a type that
 """
 
 from __future__ import with_statement
+from __future__ import print_function
 import os
 import sys
 import struct
 import operator
 
+# Python 3: cmp() builtin was removed
+def cmp(a, b):
+    return (a > b) - (a < b)
+
 # header magic
-XPT_MAGIC = "XPCOM\nTypeLib\r\n\x1a"
+XPT_MAGIC = b"XPCOM\nTypeLib\r\n\x1a"
 TYPELIB_VERSION = (1, 2)
 
 
@@ -94,9 +99,7 @@ def M_add_class_attribs(attribs):
 
 
 def enum(*names):
-    class Foo(object):
-        __metaclass__ = M_add_class_attribs(enumerate(names))
-
+    class Foo(object, metaclass=M_add_class_attribs(enumerate(names))):
         def __setattr__(self, name, value):  # this makes it read-only
             raise NotImplementedError
     return Foo()
@@ -158,11 +161,20 @@ class Type(object):
     def __cmp__(self, other):
         return (
             # First make sure we have two Types of the same type (no pun intended!)
-            cmp(type(self), type(other)) or
+            cmp(type(self).__name__, type(other).__name__) or
             cmp(self.pointer, other.pointer) or
             cmp(self.reference, other.reference)
         )
 
+    def __lt__(self, other):
+        return self.__cmp__(other) < 0
+
+    def __eq__(self, other):
+        return self.__cmp__(other) == 0
+
+    def __hash__(self):
+        return hash((type(self).__name__, self.pointer, self.reference))
+
     @staticmethod
     def decodeflags(byte):
         """
@@ -249,6 +261,10 @@ class SimpleType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def get(data, tag, flags):
         """
@@ -303,6 +319,10 @@ class InterfaceType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def read(typelib, map, data_pool, offset, flags):
         """
@@ -364,6 +384,10 @@ class InterfaceIsType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def read(typelib, map, data_pool, offset, flags):
         """
@@ -425,6 +449,10 @@ class ArrayType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def read(typelib, map, data_pool, offset, flags):
         """
@@ -483,6 +511,10 @@ class StringWithSizeType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def read(typelib, map, data_pool, offset, flags):
         """
@@ -539,6 +571,10 @@ class WideStringWithSizeType(Type):
             cmp(self.tag, other.tag)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    __hash__ = Type.__hash__
+
     @staticmethod
     def read(typelib, map, data_pool, offset, flags):
         """
@@ -604,6 +640,10 @@ class Param(object):
             cmp(self.optional, other.optional)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    def __hash__(self): return id(self)
+
     @staticmethod
     def decodeflags(byte):
         """
@@ -740,6 +780,10 @@ class Method(object):
             cmp(self.result, other.result)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    def __hash__(self): return id(self)
+
     def read_params(self, typelib, map, data_pool, offset, num_args):
         """
         Read |num_args| ParamDescriptors representing this Method's arguments
@@ -851,7 +895,7 @@ class Method(object):
         """
         if self.name:
             self._name_offset = file.tell() - data_pool_offset + 1
-            file.write(self.name + "\x00")
+            file.write(self.name.encode('utf-8') + b"\x00")
         else:
             self._name_offset = 0
 
@@ -884,6 +928,10 @@ class Constant(object):
             cmp(self.value, other.value)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    def __hash__(self): return id(self)
+
     @staticmethod
     def read(typelib, map, data_pool, offset):
         """
@@ -928,7 +976,7 @@ class Constant(object):
         """
         if self.name:
             self._name_offset = file.tell() - data_pool_offset + 1
-            file.write(self.name + "\x00")
+            file.write(self.name.encode('utf-8') + b"\x00")
         else:
             self._name_offset = 0
 
@@ -1026,6 +1074,10 @@ class Interface(object):
             cmp(self.main_process_scriptable_only, other.main_process_scriptable_only)
         )
 
+    def __lt__(self, other): return self.__cmp__(other) < 0
+    def __eq__(self, other): return self.__cmp__(other) == 0
+    # __hash__ already defined above
+
     def read_descriptor(self, typelib, map, data_pool):
         offset = self._descriptor_offset
         if offset == 0:
@@ -1114,12 +1166,12 @@ class Interface(object):
         """
         if self.name:
             self._name_offset = file.tell() - data_pool_offset + 1
-            file.write(self.name + "\x00")
+            file.write(self.name.encode('utf-8') + b"\x00")
         else:
             self._name_offset = 0
         if self.namespace:
             self._namespace_offset = file.tell() - data_pool_offset + 1
-            file.write(self.namespace + "\x00")
+            file.write(self.namespace.encode('utf-8') + b"\x00")
         else:
             self._namespace_offset = 0
         for m in self.methods:
@@ -1157,7 +1209,7 @@ class Typelib(object):
 
         """
         def hexify(s):
-            return ''.join(["%02x" % ord(x) for x in s])
+            return ''.join(["%02x" % (x if isinstance(x, int) else ord(x)) for x in s])
 
         return "%s-%s-%s-%s-%s" % (hexify(iid[:4]), hexify(iid[4:6]),
                                    hexify(iid[6:8]), hexify(iid[8:10]),
@@ -1170,16 +1222,19 @@ class Typelib(object):
 
         """
         s = iid_str.replace('-', '')
-        return ''.join([chr(int(s[i:i+2], 16)) for i in range(0, len(s), 2)])
+        return bytes([int(s[i:i+2], 16) for i in range(0, len(s), 2)])
 
     @staticmethod
     def read_string(map, data_pool, offset):
         if offset == 0:
             return ""
-        sz = map.find('\x00', data_pool + offset - 1)
+        sz = map.find(b'\x00', data_pool + offset - 1)
         if sz == -1:
             return ""
-        return map[data_pool + offset - 1:sz]
+        result = map[data_pool + offset - 1:sz]
+        if isinstance(result, bytes):
+            result = result.decode('utf-8', 'replace')
+        return result
 
     @staticmethod
     def read(input_file):
@@ -1192,7 +1247,7 @@ class Typelib(object):
         filename = ""
         data = None
         expected_size = None
-        if isinstance(input_file, basestring):
+        if isinstance(input_file, str):
             filename = input_file
             with open(input_file, "rb") as f:
                 st = os.fstat(f.fileno())
@@ -1272,11 +1327,11 @@ class Typelib(object):
         headersize = (Typelib._header.size + 1)
         if headersize % 4:
             headersize += 4 - headersize % 4
-        fd.write("\x00" * headersize)
+        fd.write(b"\x00" * headersize)
         # save this offset, it's the interface directory offset.
         interface_directory_offset = fd.tell()
         # write out space for an interface directory
-        fd.write("\x00" * Interface._direntry.size * len(self.interfaces))
+        fd.write(b"\x00" * Interface._direntry.size * len(self.interfaces))
         # save this offset, it's the data pool offset.
         data_pool_offset = fd.tell()
         # write out all the interface descriptors to the data pool
@@ -1309,7 +1364,7 @@ class Typelib(object):
 
         """
         self._sanityCheck()
-        if isinstance(output_file, basestring):
+        if isinstance(output_file, str):
             with open(output_file, "wb") as f:
                 self.writefd(f)
         else:
@@ -1392,7 +1447,7 @@ def xpt_link(inputs):
         return Typelib.read(i)
 
     if not inputs:
-        print >>sys.stderr, "Usage: xpt_link <destination file> <input files>"
+        print("Usage: xpt_link <destination file> <input files>", file=sys.stderr)
         return None
     # This is the aggregate list of interfaces.
     interfaces = []
@@ -1532,7 +1587,7 @@ def xpt_link(inputs):
 
 if __name__ == '__main__':
     if len(sys.argv) < 3:
-        print >>sys.stderr, "xpt <dump|link> <files>"
+        print("xpt <dump|link> <files>", file=sys.stderr)
         sys.exit(1)
     if sys.argv[1] == 'dump':
         xpt_dump(sys.argv[2])
diff --git a/xulrunner/app/install_app.py b/xulrunner/app/install_app.py
index 6be8c5ecb5..d7707f2426 100644
--- a/xulrunner/app/install_app.py
+++ b/xulrunner/app/install_app.py
@@ -5,12 +5,13 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # Min version of python is 2.7
+from __future__ import print_function
 import sys
 if ((sys.version_info.major != 2) or (sys.version_info.minor < 7)):
     raise Exception("You need to use Python version 2.7 or higher")
 
 import os, shutil, re, zipfile
-from ConfigParser import SafeConfigParser
+from configparser import SafeConfigParser
 
 # Platform-specific support
 # see https://developer.mozilla.org/en/XULRunner/Deploying_XULRunner_1.8
@@ -215,7 +216,7 @@ def handleCommandLine():
     except exn:
         shutil.rmtree(cmds.installDir)
         raise exn
-    print cmds.appName + " application installed to " + cmds.installDir
+    print(cmds.appName + " application installed to " + cmds.installDir)
 
 if __name__ == '__main__':
     handleCommandLine()
