Bug 1397849 - Enable py2 and py3 linter on testing/mozbase. r?ahal draft
authorSteve Armand <stevea1@mac.com>
Mon, 25 Sep 2017 22:57:18 -0400
changeset 683667 a72110096f79c215ab4a269dd80f4d19e7642dc1
parent 683444 7ca5c2de815431caaba0e5b4c8d660f34c0e3f74
child 736692 8be39c7e249a5a40d4332c0f1bd907a73d597257
push id85425
push userbmo:stevea1@mac.com
push dateFri, 20 Oct 2017 01:12:04 +0000
reviewersahal
bugs1397849
milestone58.0a1
Bug 1397849 - Enable py2 and py3 linter on testing/mozbase. r?ahal MozReview-Commit-ID: GnaVLhtO4un
testing/mozbase/docs/_static/structured_example.py
testing/mozbase/docs/conf.py
testing/mozbase/manifestparser/manifestparser/__init__.py
testing/mozbase/manifestparser/manifestparser/cli.py
testing/mozbase/manifestparser/manifestparser/expression.py
testing/mozbase/manifestparser/manifestparser/filters.py
testing/mozbase/manifestparser/manifestparser/ini.py
testing/mozbase/manifestparser/manifestparser/manifestparser.py
testing/mozbase/manifestparser/setup.py
testing/mozbase/manifestparser/tests/test_chunking.py
testing/mozbase/manifestparser/tests/test_convert_directory.py
testing/mozbase/manifestparser/tests/test_convert_symlinks.py
testing/mozbase/manifestparser/tests/test_default_overrides.py
testing/mozbase/manifestparser/tests/test_expressionparser.py
testing/mozbase/manifestparser/tests/test_filters.py
testing/mozbase/manifestparser/tests/test_manifestparser.py
testing/mozbase/manifestparser/tests/test_read_ini.py
testing/mozbase/manifestparser/tests/test_testmanifest.py
testing/mozbase/mozcrash/mozcrash/__init__.py
testing/mozbase/mozcrash/mozcrash/mozcrash.py
testing/mozbase/mozcrash/setup.py
testing/mozbase/mozcrash/tests/test.py
testing/mozbase/mozdebug/mozdebug/__init__.py
testing/mozbase/mozdebug/mozdebug/mozdebug.py
testing/mozbase/mozdebug/setup.py
testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
testing/mozbase/mozdevice/mozdevice/__init__.py
testing/mozbase/mozdevice/mozdevice/adb.py
testing/mozbase/mozdevice/mozdevice/adb_android.py
testing/mozbase/mozdevice/mozdevice/adb_b2g.py
testing/mozbase/mozdevice/mozdevice/devicemanager.py
testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
testing/mozbase/mozdevice/mozdevice/dmcli.py
testing/mozbase/mozdevice/mozdevice/droid.py
testing/mozbase/mozdevice/mozdevice/version_codes.py
testing/mozbase/mozdevice/setup.py
testing/mozbase/mozfile/mozfile/mozfile.py
testing/mozbase/mozfile/setup.py
testing/mozbase/mozfile/tests/stubs.py
testing/mozbase/mozfile/tests/test_extract.py
testing/mozbase/mozfile/tests/test_load.py
testing/mozbase/mozfile/tests/test_move_remove.py
testing/mozbase/mozfile/tests/test_tempdir.py
testing/mozbase/mozfile/tests/test_tempfile.py
testing/mozbase/mozfile/tests/test_url.py
testing/mozbase/mozhttpd/mozhttpd/__init__.py
testing/mozbase/mozhttpd/mozhttpd/handlers.py
testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
testing/mozbase/mozhttpd/setup.py
testing/mozbase/mozhttpd/tests/api.py
testing/mozbase/mozhttpd/tests/baseurl.py
testing/mozbase/mozhttpd/tests/basic.py
testing/mozbase/mozhttpd/tests/filelisting.py
testing/mozbase/mozhttpd/tests/paths.py
testing/mozbase/mozhttpd/tests/requestlog.py
testing/mozbase/mozinfo/mozinfo/__init__.py
testing/mozbase/mozinfo/mozinfo/mozinfo.py
testing/mozbase/mozinfo/mozinfo/string_version.py
testing/mozbase/mozinfo/setup.py
testing/mozbase/mozinfo/tests/test.py
testing/mozbase/mozinstall/mozinstall/__init__.py
testing/mozbase/mozinstall/mozinstall/mozinstall.py
testing/mozbase/mozinstall/setup.py
testing/mozbase/mozinstall/tests/test.py
testing/mozbase/mozleak/mozleak/__init__.py
testing/mozbase/mozleak/mozleak/leaklog.py
testing/mozbase/mozleak/setup.py
testing/mozbase/mozlog/mozlog/__init__.py
testing/mozbase/mozlog/mozlog/commandline.py
testing/mozbase/mozlog/mozlog/formatters/__init__.py
testing/mozbase/mozlog/mozlog/formatters/base.py
testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
testing/mozbase/mozlog/mozlog/formatters/html/html.py
testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
testing/mozbase/mozlog/mozlog/formatters/machformatter.py
testing/mozbase/mozlog/mozlog/formatters/process.py
testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
testing/mozbase/mozlog/mozlog/formatters/unittest.py
testing/mozbase/mozlog/mozlog/formatters/xunit.py
testing/mozbase/mozlog/mozlog/handlers/__init__.py
testing/mozbase/mozlog/mozlog/handlers/base.py
testing/mozbase/mozlog/mozlog/handlers/bufferhandler.py
testing/mozbase/mozlog/mozlog/handlers/statushandler.py
testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
testing/mozbase/mozlog/mozlog/logtypes.py
testing/mozbase/mozlog/mozlog/proxy.py
testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
testing/mozbase/mozlog/mozlog/reader.py
testing/mozbase/mozlog/mozlog/scripts/__init__.py
testing/mozbase/mozlog/mozlog/scripts/format.py
testing/mozbase/mozlog/mozlog/scripts/logmerge.py
testing/mozbase/mozlog/mozlog/scripts/unstable.py
testing/mozbase/mozlog/mozlog/stdadapter.py
testing/mozbase/mozlog/mozlog/structuredlog.py
testing/mozbase/mozlog/mozlog/unstructured/__init__.py
testing/mozbase/mozlog/mozlog/unstructured/logger.py
testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
testing/mozbase/mozlog/setup.py
testing/mozbase/mozlog/tests/test_logger.py
testing/mozbase/mozlog/tests/test_logtypes.py
testing/mozbase/mozlog/tests/test_structured.py
testing/mozbase/moznetwork/moznetwork/__init__.py
testing/mozbase/moznetwork/moznetwork/moznetwork.py
testing/mozbase/moznetwork/setup.py
testing/mozbase/moznetwork/tests/test.py
testing/mozbase/mozprocess/mozprocess/processhandler.py
testing/mozbase/mozprocess/mozprocess/winprocess.py
testing/mozbase/mozprocess/setup.py
testing/mozbase/mozprocess/tests/infinite_loop.py
testing/mozbase/mozprocess/tests/proccountfive.py
testing/mozbase/mozprocess/tests/proclaunch.py
testing/mozbase/mozprocess/tests/procnonewline.py
testing/mozbase/mozprocess/tests/proctest.py
testing/mozbase/mozprocess/tests/test_mozprocess.py
testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
testing/mozbase/mozprocess/tests/test_mozprocess_kill_broad_wait.py
testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
testing/mozbase/mozprocess/tests/test_mozprocess_output.py
testing/mozbase/mozprocess/tests/test_mozprocess_params.py
testing/mozbase/mozprocess/tests/test_mozprocess_poll.py
testing/mozbase/mozprocess/tests/test_mozprocess_wait.py
testing/mozbase/mozprocess/tests/test_process_reader.py
testing/mozbase/mozprofile/mozprofile/__init__.py
testing/mozbase/mozprofile/mozprofile/addons.py
testing/mozbase/mozprofile/mozprofile/cli.py
testing/mozbase/mozprofile/mozprofile/diff.py
testing/mozbase/mozprofile/mozprofile/permissions.py
testing/mozbase/mozprofile/mozprofile/prefs.py
testing/mozbase/mozprofile/mozprofile/profile.py
testing/mozbase/mozprofile/mozprofile/view.py
testing/mozbase/mozprofile/setup.py
testing/mozbase/mozprofile/tests/addon_stubs.py
testing/mozbase/mozprofile/tests/addonid.py
testing/mozbase/mozprofile/tests/bug758250.py
testing/mozbase/mozprofile/tests/bug785146.py
testing/mozbase/mozprofile/tests/permissions.py
testing/mozbase/mozprofile/tests/server_locations.py
testing/mozbase/mozprofile/tests/test_addons.py
testing/mozbase/mozprofile/tests/test_clone_cleanup.py
testing/mozbase/mozprofile/tests/test_nonce.py
testing/mozbase/mozprofile/tests/test_preferences.py
testing/mozbase/mozprofile/tests/test_profile.py
testing/mozbase/mozprofile/tests/test_profile_view.py
testing/mozbase/mozrunner/mozrunner/__init__.py
testing/mozbase/mozrunner/mozrunner/application.py
testing/mozbase/mozrunner/mozrunner/base/__init__.py
testing/mozbase/mozrunner/mozrunner/base/browser.py
testing/mozbase/mozrunner/mozrunner/base/device.py
testing/mozbase/mozrunner/mozrunner/base/runner.py
testing/mozbase/mozrunner/mozrunner/cli.py
testing/mozbase/mozrunner/mozrunner/devices/__init__.py
testing/mozbase/mozrunner/mozrunner/devices/android_device.py
testing/mozbase/mozrunner/mozrunner/devices/autophone.py
testing/mozbase/mozrunner/mozrunner/devices/base.py
testing/mozbase/mozrunner/mozrunner/devices/emulator.py
testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
testing/mozbase/mozrunner/mozrunner/errors.py
testing/mozbase/mozrunner/mozrunner/runners.py
testing/mozbase/mozrunner/mozrunner/utils.py
testing/mozbase/mozrunner/setup.py
testing/mozbase/mozrunner/tests/mozrunnertest.py
testing/mozbase/mozrunner/tests/test_crash.py
testing/mozbase/mozrunner/tests/test_interactive.py
testing/mozbase/mozrunner/tests/test_start.py
testing/mozbase/mozrunner/tests/test_states.py
testing/mozbase/mozrunner/tests/test_stop.py
testing/mozbase/mozrunner/tests/test_threads.py
testing/mozbase/mozrunner/tests/test_wait.py
testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
testing/mozbase/mozscreenshot/setup.py
testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
testing/mozbase/mozsystemmonitor/setup.py
testing/mozbase/mozsystemmonitor/tests/test_resource_monitor.py
testing/mozbase/moztest/moztest/__init__.py
testing/mozbase/moztest/moztest/adapters/__init__.py
testing/mozbase/moztest/moztest/adapters/unit.py
testing/mozbase/moztest/moztest/output/autolog.py
testing/mozbase/moztest/moztest/output/base.py
testing/mozbase/moztest/moztest/output/xunit.py
testing/mozbase/moztest/moztest/results.py
testing/mozbase/moztest/moztest/selftest/fixtures.py
testing/mozbase/moztest/moztest/selftest/output.py
testing/mozbase/moztest/setup.py
testing/mozbase/moztest/tests/test.py
testing/mozbase/mozversion/mozversion/__init__.py
testing/mozbase/mozversion/mozversion/errors.py
testing/mozbase/mozversion/mozversion/mozversion.py
testing/mozbase/mozversion/setup.py
testing/mozbase/mozversion/tests/test_apk.py
testing/mozbase/mozversion/tests/test_b2g.py
testing/mozbase/mozversion/tests/test_binary.py
testing/mozbase/mozversion/tests/test_sources.py
testing/mozbase/setup_development.py
testing/mozbase/versioninfo.py
tools/lint/py2.yml
tools/lint/py3.yml
--- a/testing/mozbase/docs/_static/structured_example.py
+++ b/testing/mozbase/docs/_static/structured_example.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import argparse
 import sys
 import traceback
 import types
 
 from mozlog import commandline, get_default_logger
 
 
--- a/testing/mozbase/docs/conf.py
+++ b/testing/mozbase/docs/conf.py
@@ -6,16 +6,18 @@
 # This file is execfile()d with the current directory set to its containing dir.
 #
 # Note that not all possible configuration values are present in this
 # autogenerated file.
 #
 # All configuration values have a default; values that are commented out
 # serve to show the default.
 
+from __future__ import absolute_import
+
 import sys
 import os
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 here = os.path.dirname(os.path.abspath(__file__))
 parent = os.path.dirname(here)
--- a/testing/mozbase/manifestparser/manifestparser/__init__.py
+++ b/testing/mozbase/manifestparser/manifestparser/__init__.py
@@ -1,8 +1,10 @@
 # flake8: noqa
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .manifestparser import *
 from .expression import *
 from .ini import *
--- a/testing/mozbase/manifestparser/manifestparser/cli.py
+++ b/testing/mozbase/manifestparser/manifestparser/cli.py
@@ -1,16 +1,17 @@
 #!/usr/bin/env python
 # 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/.
 
 """
 Mozilla universal manifest parser
 """
+from __future__ import absolute_import, print_function
 
 from optparse import OptionParser
 import os
 import sys
 
 from .manifestparser import (
     convert,
     ManifestParser,
@@ -76,17 +77,17 @@ class CLICommand(object):
 
 class Copy(CLICommand):
     usage = '%prog [options] copy manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ...'
 
     def __call__(self, options, args):
         # 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
         # be quite boring
         if not len(args) == 2:
             HelpCLI(self._parser)(options, ['copy'])
             return
 
@@ -127,31 +128,31 @@ class CreateCLI(CLICommand):
 
         # add the directories to the manifest
         for arg in args:
             assert os.path.exists(arg)
             assert os.path.isdir(arg)
             manifest = convert(args, pattern=options.pattern, ignore=options.ignore,
                                write=options.in_place)
         if manifest:
-            print manifest
+            print(manifest)
 
 
 class WriteCLI(CLICommand):
     """
     write a manifest based on a query
     """
     usage = '%prog [options] write manifest <manifest> -tag1 -tag2 --key1=value1 --key2=value2 ...'
 
     def __call__(self, options, args):
 
         # 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
         # be quite boring
         if not args:
             HelpCLI(self._parser)(options, ['write'])
             return
 
@@ -170,32 +171,32 @@ class HelpCLI(CLICommand):
     """
     usage = '%prog [options] help [command]'
 
     def __call__(self, options, args):
         if len(args) == 1 and args[0] in commands:
             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):
     """
     update the tests as listed in a manifest from a directory
     """
     usage = '%prog [options] update manifest directory -tag1 -tag2 --key1=value1 --key2=value2 ...'
 
     def __call__(self, options, args):
         # 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
         # be quite boring
         if not len(args) == 2:
             HelpCLI(self._parser)(options, ['update'])
             return
 
--- a/testing/mozbase/manifestparser/manifestparser/expression.py
+++ b/testing/mozbase/manifestparser/manifestparser/expression.py
@@ -1,16 +1,20 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import re
 import sys
 import traceback
 
+from six import reraise
+
 __all__ = ['parse', 'ParseError', 'ExpressionParser']
 
 # expr.py
 # from:
 # http://k0s.org/mozilla/hg/expressionparser
 # http://hg.mozilla.org/users/tmielczarek_mozilla.com/expressionparser
 
 # Implements a top-down parser/evaluator for simple boolean expressions.
@@ -300,20 +304,18 @@ class ExpressionParser(object):
         """
         try:
             self.iter = self._tokenize()
             self.token = self.iter.next()
             return self.expression()
         except:
             extype, ex, tb = sys.exc_info()
             formatted = ''.join(traceback.format_exception_only(extype, ex))
-            raise ParseError("could not parse: "
-                             "%s\nexception: %svariables: %s" % (self.text,
-                                                                 formatted,
-                                                                 self.valuemapping)), None, tb
+            reraise(ParseError("could not parse: %s\nexception: %svariables: %s" %
+                    (self.text, formatted, self.valuemapping)), None, tb)
 
     __call__ = parse
 
 
 def parse(text, **values):
     """
     Parse and evaluate a boolean expression.
     :param text: The expression to parse, as a string.
--- a/testing/mozbase/manifestparser/manifestparser/filters.py
+++ b/testing/mozbase/manifestparser/manifestparser/filters.py
@@ -3,16 +3,18 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """
 A filter is a callable that accepts an iterable of test objects and a
 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 __future__ import absolute_import
+
 from collections import defaultdict, MutableSequence
 import itertools
 import os
 
 from .expression import (
     parse,
     ParseError,
 )
--- a/testing/mozbase/manifestparser/manifestparser/ini.py
+++ b/testing/mozbase/manifestparser/manifestparser/ini.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import sys
 
 __all__ = ['read_ini', 'combine_fields']
 
 
 class IniParseError(Exception):
     def __init__(self, fp, linenum, msg):
--- a/testing/mozbase/manifestparser/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestparser/manifestparser/manifestparser.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 from StringIO import StringIO
 import json
 import fnmatch
 import os
 import shutil
 import sys
 import types
 
@@ -370,18 +372,18 @@ class ManifestParser(object):
     def check_missing(self, tests=None):
         missing = self.missing(tests=tests)
         if missing:
             missing_paths = [test['path'] for test in missing]
             if self.strict:
                 raise IOError("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):
         """
         checks what is on the filesystem vs what is in a manifest
         returns a 2-tuple of sets:
         (missing_from_filesystem, missing_from_manifest)
         """
@@ -446,45 +448,45 @@ class ManifestParser(object):
         kwargs.update(global_kwargs)
         kwargs.update(local_kwargs)
 
         # get matching tests
         tests = self.get(tags=tags, **kwargs)
 
         # 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('%s = %s' % (key, value), file=fp)
+            print(file=fp)
 
         for test in tests:
             test = test.copy()  # don't overwrite
 
             path = test['name']
             if not os.path.isabs(path):
                 path = test['path']
                 if self.rootdir:
                     path = relpath(test['path'], self.rootdir)
                 path = denormalize_path(path)
-            print >> fp, '[%s]' % path
+            print('[%s]' % path, file=fp)
 
             # reserved keywords:
             reserved = ['path', 'name', 'here', 'manifest', 'relpath', 'ancestor-manifest']
             for key in sorted(test.keys()):
                 if key in reserved:
                     continue
                 if key in global_kwargs:
                     continue
                 if key in global_tags and not test[key]:
                     continue
-                print >> fp, '%s = %s' % (key, test[key])
-            print >> fp
+                print('%s = %s' % (key, test[key]), file=fp)
+            print(file=fp)
 
         if close:
             # close the created file
             fp.close()
 
     def __str__(self):
         fp = StringIO()
         self.write(fp=fp)
@@ -562,17 +564,17 @@ class ManifestParser(object):
         for test in tests:
             if not os.path.isabs(test['name']):
                 _relpath = relpath(test['path'], rootdir)
                 source = os.path.join(from_dir, _relpath)
                 if not os.path.exists(source):
                     message = "Missing test: '%s' does not exist!"
                     if self.strict:
                         raise IOError(message)
-                    print >> sys.stderr, message + " Skipping."
+                    print(message + " Skipping.", file=sys.stderr)
                     continue
                 destination = os.path.join(rootdir, _relpath)
                 shutil.copy(source, destination)
 
     # directory importers
 
     @classmethod
     def _walk_directories(cls, directories, callback, pattern=None, ignore=()):
@@ -667,19 +669,19 @@ class ManifestParser(object):
 
         def callback(directory, dirpath, dirnames, filenames):
             """write a manifest for each directory"""
 
             manifest_path = os.path.join(dirpath, filename)
             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)
 
         # walk the directories to gather files
         cls._walk_directories(directories, callback, pattern=pattern, ignore=ignore)
         # get manifests
         manifests = [manifest_dict[directory] for directory in _directories]
@@ -719,18 +721,18 @@ class ManifestParser(object):
             filenames = [filename for filename in filenames
                          if filename != opened_manifest_file]
             # normalize paths
             if not absolute and relative_to:
                 filenames = [relpath(filename, relative_to)
                              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)
 
         if opened_manifest_file:
             # close file
             write.close()
             manifests = [opened_manifest_file]
         else:
--- a/testing/mozbase/manifestparser/setup.py
+++ b/testing/mozbase/manifestparser/setup.py
@@ -1,30 +1,31 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = "manifestparser"
-PACKAGE_VERSION = '1.1'
+PACKAGE_VERSION = '1.2'
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Library to create and manage test manifests",
       long_description="see http://mozbase.readthedocs.org/",
       classifiers=['Programming Language :: Python :: 2.7',
                    'Programming Language :: Python :: 2 :: Only'],
                   # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
       keywords='mozilla manifests',
       author='Mozilla Automation and Testing Team',
       author_email='tools@lists.mozilla.org',
       url='https://wiki.mozilla.org/Auto-tools/Projects/Mozbase',
       license='MPL',
       zip_safe=False,
       packages=['manifestparser'],
-      install_requires=[],
+      install_requires=['six >= 1.10.0'],
       entry_points="""
       [console_scripts]
       manifestparser = manifestparser.cli:main
       """,
       )
--- a/testing/mozbase/manifestparser/tests/test_chunking.py
+++ b/testing/mozbase/manifestparser/tests/test_chunking.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 from itertools import chain
 from unittest import TestCase
 import os
 import random
 
 import mozunit
 
 from manifestparser.filters import (
--- a/testing/mozbase/manifestparser/tests/test_convert_directory.py
+++ b/testing/mozbase/manifestparser/tests/test_convert_directory.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 import unittest
 
 import mozunit
 
 from manifestparser import convert
--- a/testing/mozbase/manifestparser/tests/test_convert_symlinks.py
+++ b/testing/mozbase/manifestparser/tests/test_convert_symlinks.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 import unittest
 
 import mozunit
 
 from manifestparser import convert, ManifestParser
--- a/testing/mozbase/manifestparser/tests/test_default_overrides.py
+++ b/testing/mozbase/manifestparser/tests/test_default_overrides.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import unittest
 
 import mozunit
 
 from manifestparser import ManifestParser
 from manifestparser import combine_fields
 
--- a/testing/mozbase/manifestparser/tests/test_expressionparser.py
+++ b/testing/mozbase/manifestparser/tests/test_expressionparser.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import unittest
 
 import mozunit
 
 from manifestparser import parse
 
 
 class ExpressionParserTest(unittest.TestCase):
--- a/testing/mozbase/manifestparser/tests/test_filters.py
+++ b/testing/mozbase/manifestparser/tests/test_filters.py
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
 # flake8: noqa
 
+from __future__ import absolute_import
+
 from copy import deepcopy
 import os
 import unittest
 
 import mozunit
 
 from manifestparser.filters import (
     subsuite,
--- a/testing/mozbase/manifestparser/tests/test_manifestparser.py
+++ b/testing/mozbase/manifestparser/tests/test_manifestparser.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 import unittest
 from StringIO import StringIO
 
 import mozunit
 
--- a/testing/mozbase/manifestparser/tests/test_read_ini.py
+++ b/testing/mozbase/manifestparser/tests/test_read_ini.py
@@ -5,16 +5,18 @@ test .ini parsing
 
 ensure our .ini parser is doing what we want; to be deprecated for
 python's standard ConfigParser when 2.7 is reality so OrderedDict
 is the default:
 
 http://docs.python.org/2/library/configparser.html
 """
 
+from __future__ import absolute_import
+
 import unittest
 from manifestparser import read_ini
 from StringIO import StringIO
 
 import mozunit
 
 
 class IniParserTest(unittest.TestCase):
--- a/testing/mozbase/manifestparser/tests/test_testmanifest.py
+++ b/testing/mozbase/manifestparser/tests/test_testmanifest.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 import unittest
 
 import mozunit
 
 from manifestparser import TestManifest, ParseError
--- a/testing/mozbase/mozcrash/mozcrash/__init__.py
+++ b/testing/mozbase/mozcrash/mozcrash/__init__.py
@@ -1,10 +1,11 @@
 # flake8: noqa
 # 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/.
 """
 mozcrash is a library for getting a stack trace out of processes that have crashed
 and left behind a minidump file using the Google Breakpad library.
 """
+from __future__ import absolute_import
 
-from mozcrash import *
+from .mozcrash import *
--- a/testing/mozbase/mozcrash/mozcrash/mozcrash.py
+++ b/testing/mozbase/mozcrash/mozcrash/mozcrash.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import glob
 import os
 import re
 import shutil
 import signal
 import subprocess
 import sys
 import tempfile
@@ -100,20 +102,20 @@ def check_for_crashes(dump_directory,
                 stackwalk_output.append("stderr from minidump_stackwalk:")
                 stackwalk_output.append(info.stackwalk_stderr)
             elif info.stackwalk_stdout is not None:
                 stackwalk_output.append(info.stackwalk_stdout)
             if info.stackwalk_retcode is not None and info.stackwalk_retcode != 0:
                 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,
-                                                                     signature)
-            print '\n'.join(stackwalk_output)
-            print '\n'.join(info.stackwalk_errors)
+            print("PROCESS-CRASH | %s | application crashed [%s]" % (test_name,
+                                                                     signature))
+            print('\n'.join(stackwalk_output))
+            print('\n'.join(info.stackwalk_errors))
 
     return crash_count
 
 
 def log_crashes(logger,
                 dump_directory,
                 symbols_path,
                 process=None,
@@ -366,22 +368,22 @@ def check_for_java_exception(logcat, tes
                 logre = re.compile(r".*\): \t?(.*)")
                 m = logre.search(logcat[i + 1])
                 if m and m.group(1):
                     exception_type = m.group(1)
                 m = logre.search(logcat[i + 2])
                 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)
+                                                                         exception_location))
             else:
-                print "Automation Error: java exception in logcat at line " \
-                    "%d of %d: %s" % (i, len(logcat), line)
+                print("Automation Error: java exception in logcat at line "
+                      "%d of %d: %s" % (i, len(logcat), line))
             break
 
     return found_exception
 
 
 if mozinfo.isWin:
     import ctypes
     import uuid
--- a/testing/mozbase/mozcrash/setup.py
+++ b/testing/mozbase/mozcrash/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozcrash'
 PACKAGE_VERSION = '1.0'
 
 # dependencies
 deps = ['mozfile >= 1.0',
--- a/testing/mozbase/mozcrash/tests/test.py
+++ b/testing/mozbase/mozcrash/tests/test.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import unittest
 import subprocess
 import tempfile
 import shutil
 import urlparse
 import zipfile
 import StringIO
--- a/testing/mozbase/mozdebug/mozdebug/__init__.py
+++ b/testing/mozbase/mozdebug/mozdebug/__init__.py
@@ -22,10 +22,11 @@ debugger-specific arguments:
   debuggeePath = "toDebug"
 
   processArgs = [self.debuggerInfo.path] + self.debuggerInfo.args
   processArgs.append(debuggeePath)
 
   run_process(args, ...)
 
 """
+from __future__ import absolute_import
 
 from mozdebug import *
--- a/testing/mozbase/mozdebug/mozdebug/mozdebug.py
+++ b/testing/mozbase/mozdebug/mozdebug/mozdebug.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import os
 import mozinfo
 from collections import namedtuple
 from distutils.spawn import find_executable
 from subprocess import check_output
 
 __all__ = ['get_debugger_info',
            'get_default_debugger_name',
@@ -145,17 +147,17 @@ def get_debugger_info(debugger, debugger
                 if os.path.exists(candidate):
                     debuggerPath = candidate
                     break
         else:
             if os.path.exists(debugger):
                 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()
 
     def get_debugger_info(type, default):
         if debuggerName in _DEBUGGER_INFO and type in _DEBUGGER_INFO[debuggerName]:
             return _DEBUGGER_INFO[debuggerName][type]
         return default
--- a/testing/mozbase/mozdebug/setup.py
+++ b/testing/mozbase/mozdebug/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_VERSION = '0.1'
 
 setup(name='mozdebug',
       version=PACKAGE_VERSION,
       description="Utilities for running applications under native code debuggers "
--- 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
@@ -1,15 +1,18 @@
 """
  This test is to test devices that adbd does not get started as root.
  Specifically devices that have ro.secure == 1 and ro.debuggable == 1
 
  Running this test case requires various reboots which makes it a
  very slow test case to run.
 """
+
+from __future__ import absolute_import, print_function
+
 import unittest
 import sys
 
 from mozdevice import DeviceManagerADB
 
 
 class TestFileOperations(unittest.TestCase):
 
@@ -32,18 +35,18 @@ class TestFileOperations(unittest.TestCa
     def tearDown(self):
         dm = DeviceManagerADB()
         dm.reboot()
 
 
 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()
--- a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
@@ -28,16 +28,17 @@
  - processExist
 
  I assume these functions are only useful for Android
  - getAppRoot()
  - updateApp()
  - uninstallApp()
  - uninstallAppAndReboot()
 """
+from __future__ import absolute_import, print_function
 
 import os
 import re
 import socket
 import sys
 import tempfile
 import unittest
 from StringIO import StringIO
@@ -202,18 +203,18 @@ class TestOther(DeviceManagerADBTestCase
 
     def test_port_forwarding_error(self):
         self.assertRaises(DMError, self.dm.forward, "", "")
 
 
 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 " \
-            "'adb remount' has been run before running this test case. Please reboot the device " \
-            "and try again."
+        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.")
         sys.exit(1)
 
     unittest.main()
--- a/testing/mozbase/mozdevice/mozdevice/__init__.py
+++ b/testing/mozbase/mozdevice/mozdevice/__init__.py
@@ -1,14 +1,17 @@
 # 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 adb import ADBError, ADBRootError, ADBTimeoutError, ADBProcess, ADBCommand, ADBHost, ADBDevice
-from adb_android import ADBAndroid
-from adb_b2g import ADBB2G
-from devicemanager import DeviceManager, DMError
-from devicemanagerADB import DeviceManagerADB
-from droid import DroidADB
+from __future__ import absolute_import
+
+from .adb import ADBError, ADBRootError, ADBTimeoutError
+from .adb import ADBProcess, ADBCommand, ADBHost, ADBDevice
+from .adb_android import ADBAndroid
+from .adb_b2g import ADBB2G
+from .devicemanager import DeviceManager, DMError
+from .devicemanagerADB import DeviceManagerADB
+from .droid import DroidADB
 
 __all__ = ['ADBError', 'ADBRootError', 'ADBTimeoutError', 'ADBProcess', 'ADBCommand', 'ADBHost',
            'ADBDevice', 'ADBAndroid', 'ADBB2G', 'DeviceManager', 'DMError',
            'DeviceManagerADB', 'DroidADB']
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import posixpath
 import re
 import shutil
 import subprocess
 import tempfile
 import time
 import traceback
--- a/testing/mozbase/mozdevice/mozdevice/adb_android.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb_android.py
@@ -1,35 +1,37 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import os
 import re
 import time
 
 from abc import ABCMeta
 
-import version_codes
+from . import version_codes
 
-from adb import ADBDevice, ADBError, ADBRootError
+from .adb import ADBDevice, ADBError, ADBRootError
 
 
 class ADBAndroid(ADBDevice):
     """ADBAndroid implements :class:`ADBDevice` providing Android-specific
     functionality.
 
     ::
 
        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,
                  adb='adb',
                  adb_host=None,
                  adb_port=None,
@@ -85,17 +87,17 @@ class ADBAndroid(ADBDevice):
         # usage:  setenforce [ Enforcing | Permissive | 1 | 0 ]
         # getenforce returns either Enforcing or Permissive
 
         try:
             self.selinux = True
             if self.shell_output('getenforce', timeout=timeout) != 'Permissive':
                 self._logger.info('Setting SELinux Permissive Mode')
                 self.shell_output("setenforce Permissive", timeout=timeout, root=True)
-        except (ADBError, ADBRootError), e:
+        except (ADBError, ADBRootError) as e:
             self._logger.warning('Unable to set SELinux Permissive due to %s.' % e)
             self.selinux = False
 
         self.version = int(self.shell_output("getprop ro.build.version.sdk",
                                              timeout=timeout))
 
     def reboot(self, timeout=None):
         """Reboots the device.
--- a/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
@@ -1,17 +1,19 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import traceback
 
 import mozfile
 
-from adb import ADBDevice, ADBError
+from .adb import ADBDevice, ADBError
 
 
 class ADBB2G(ADBDevice):
     """ADBB2G implements :class:`ADBDevice` providing B2G-specific
     functionality.
 
     ::
 
--- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import hashlib
 import mozlog
 import logging
 import os
 import posixpath
 import re
 import struct
 import StringIO
--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+++ b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
@@ -1,25 +1,27 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import logging
 import re
 import os
 import tempfile
 import time
 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):
     """
     Implementation of DeviceManager interface that uses the Android "adb"
     utility to communicate with the device. Normally used to communicate
     with a device that is directly connected with the host machine over a USB
     port.
--- a/testing/mozbase/mozdevice/mozdevice/dmcli.py
+++ b/testing/mozbase/mozdevice/mozdevice/dmcli.py
@@ -1,15 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """
 Command-line client to control a device
 """
+from __future__ import absolute_import, print_function
 
 import errno
 import logging
 import os
 import posixpath
 import StringIO
 import sys
 import mozdevice
@@ -204,33 +205,33 @@ class DMCli(object):
 
         if host and not port:
             port = 5555
         return mozdevice.DroidADB(packageName=packagename,
                                   host=host, port=port,
                                   logLevel=logLevel)
 
     def deviceroot(self, args):
-        print self.dm.deviceRoot
+        print(self.dm.deviceRoot)
 
     def push(self, args):
         (src, dest) = (args.local_file, args.remote_file)
         if os.path.isdir(src):
             self.dm.pushDir(src, dest)
         else:
             dest_is_dir = dest[-1] == '/' or self.dm.dirExists(dest)
             dest = posixpath.normpath(dest)
             if dest_is_dir:
                 dest = posixpath.join(dest, os.path.basename(src))
             self.dm.pushFile(src, dest)
 
     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)
         if self.dm.dirExists(src):
             self.dm.getDirectory(src, dest)
         else:
             self.dm.getFile(src, dest)
 
@@ -246,84 +247,84 @@ class DMCli(object):
 
     def launchapp(self, args):
         self.dm.launchApplication(args.appname, args.activity_name,
                                   args.intent, url=args.url,
                                   failIfRunning=(not args.no_fail_if_running))
 
     def listapps(self, args):
         for app in self.dm.getInstalledApps():
-            print app
+            print(app)
 
     def stopapp(self, args):
         self.dm.stopApplication(args.appname)
 
     def kill(self, args):
         for name in args.process_name:
             self.dm.killProcess(name)
 
     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()):
             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()
 
     def reboot(self, args):
         self.dm.reboot(wait=args.wait)
 
     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):
         self.dm.mkDir(args.remote_dir)
 
     def rmdir(self, args):
         self.dm.removeDir(args.remote_dir)
 
     def screencap(self, args):
         self.dm.saveScreenshot(args.png_file)
 
     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):
         mozEnv = None
         if args.mozenv:
             mozEnv = {}
             keyvals = args.mozenv.split()
             for keyval in keyvals:
--- a/testing/mozbase/mozdevice/mozdevice/droid.py
+++ b/testing/mozbase/mozdevice/mozdevice/droid.py
@@ -1,20 +1,22 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import StringIO
 import re
 import time
 
-import version_codes
+from mozdevice import version_codes
 
-from devicemanagerADB import DeviceManagerADB
-from devicemanager import DMError
+from .devicemanagerADB import DeviceManagerADB
+from .devicemanager import DMError
 
 
 class DroidMixin(object):
     """Mixin to extend DeviceManager with Android-specific functionality"""
 
     _stopApplicationNeedsRoot = True
 
     def _getExtraAmStartArgs(self):
--- a/testing/mozbase/mozdevice/mozdevice/version_codes.py
+++ b/testing/mozbase/mozdevice/mozdevice/version_codes.py
@@ -2,16 +2,17 @@
 # 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/.
 
 """
 VERSION CODES of the android releases.
 
 See http://developer.android.com/reference/android/os/Build.VERSION_CODES.html.
 """
+from __future__ import absolute_import
 
 # Magic version number for a current development build, which has
 # not yet turned into an official release.
 CUR_DEVELOPMENT = 10000
 
 # October 2008: The original, first, version of Android
 BASE = 1
 # February 2009: First Android update, officially called 1.1
--- a/testing/mozbase/mozdevice/setup.py
+++ b/testing/mozbase/mozdevice/setup.py
@@ -1,13 +1,14 @@
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozdevice'
 PACKAGE_VERSION = '0.51'
 
 deps = ['mozfile >= 1.0',
         'mozlog >= 3.0',
--- a/testing/mozbase/mozfile/mozfile/mozfile.py
+++ b/testing/mozbase/mozfile/mozfile/mozfile.py
@@ -1,17 +1,17 @@
 # -*- 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 absolute_import, print_function
 
 from contextlib import contextmanager
 import errno
 import os
 import stat
 import time
 import warnings
 
@@ -50,17 +50,17 @@ def extract_zip(src, dest):
     import zipfile
 
     if isinstance(src, zipfile.ZipFile):
         bundle = src
     else:
         try:
             bundle = zipfile.ZipFile(src)
         except Exception:
-            print "src: %s" % src
+            print("src: %s" % src)
             raise
 
     namelist = bundle.namelist()
 
     for name in namelist:
         filename = os.path.realpath(os.path.join(dest, name))
         if name.endswith('/'):
             if not os.path.isdir(filename):
@@ -156,18 +156,18 @@ def _call_windows_retry(func, args=(), r
             if e.errno not in (errno.EACCES, errno.ENOTEMPTY):
                 raise
 
             if retry_count == retry_max:
                 raise
 
             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
             break
 
 
 def remove(path):
     """Removes the specified file, link, or directory tree.
--- a/testing/mozbase/mozfile/setup.py
+++ b/testing/mozbase/mozfile/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_NAME = 'mozfile'
 PACKAGE_VERSION = '1.2'
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
--- a/testing/mozbase/mozfile/tests/stubs.py
+++ b/testing/mozbase/mozfile/tests/stubs.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 
 
 # stub file paths
 files = [('foo.txt',),
          ('foo', 'bar.txt',),
--- a/testing/mozbase/mozfile/tests/test_extract.py
+++ b/testing/mozbase/mozfile/tests/test_extract.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import, print_function
+
 import os
 import shutil
 import tarfile
 import tempfile
 import unittest
 import zipfile
 
 import mozunit
@@ -18,17 +20,17 @@ class TestExtract(unittest.TestCase):
     """test extracting archives"""
 
     def ensure_directory_contents(self, directory):
         """ensure the directory contents match"""
         for f in stubs.files:
             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()
                 self.assertTrue(contents == f[-1])
 
     def test_extract_zipfile(self):
         """test extracting a zipfile"""
         _zipfile = self.create_zip()
--- a/testing/mozbase/mozfile/tests/test_load.py
+++ b/testing/mozbase/mozfile/tests/test_load.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 """
 tests for mozfile.load
 """
 
+from __future__ import absolute_import
+
 import mozhttpd
 import os
 import tempfile
 import unittest
 
 import mozunit
 
 from mozfile import load
--- a/testing/mozbase/mozfile/tests/test_move_remove.py
+++ b/testing/mozbase/mozfile/tests/test_move_remove.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import stat
 import shutil
 import threading
 import time
 import unittest
 import errno
 from contextlib import contextmanager
--- a/testing/mozbase/mozfile/tests/test_tempdir.py
+++ b/testing/mozbase/mozfile/tests/test_tempdir.py
@@ -3,16 +3,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/.
 
 """
 tests for mozfile.TemporaryDirectory
 """
 
+from __future__ import absolute_import
+
 from mozfile import TemporaryDirectory
 import os
 import unittest
 
 import mozunit
 
 
 class TestTemporaryDirectory(unittest.TestCase):
--- a/testing/mozbase/mozfile/tests/test_tempfile.py
+++ b/testing/mozbase/mozfile/tests/test_tempfile.py
@@ -2,16 +2,17 @@
 
 # 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/.
 
 """
 tests for mozfile.NamedTemporaryFile
 """
+from __future__ import absolute_import
 
 import mozfile
 import os
 import unittest
 
 import mozunit
 
 
--- a/testing/mozbase/mozfile/tests/test_url.py
+++ b/testing/mozbase/mozfile/tests/test_url.py
@@ -1,13 +1,14 @@
 #!/usr/bin/env python
 
 """
 tests for is_url
 """
+from __future__ import absolute_import
 
 import unittest
 from mozfile import is_url
 
 import mozunit
 
 
 class TestIsUrl(unittest.TestCase):
--- a/testing/mozbase/mozhttpd/mozhttpd/__init__.py
+++ b/testing/mozbase/mozhttpd/mozhttpd/__init__.py
@@ -36,13 +36,14 @@ content from the current directory, defi
   httpd = mozhttpd.MozHttpd(port=8080, docroot='.',
                             urlhandlers = [ { 'method': 'GET',
                                               'path': '/api/resources/([^/]+)/?',
                                               'function': resource_get } ])
   print "Serving '%s' at %s:%s" % (httpd.docroot, httpd.host, httpd.port)
   httpd.start(block=True)
 
 """
+from __future__ import absolute_import
 
-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']
--- a/testing/mozbase/mozhttpd/mozhttpd/handlers.py
+++ b/testing/mozbase/mozhttpd/mozhttpd/handlers.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import json
 
 
 def json_response(func):
     """ Translates results of 'func' into a JSON response. """
     def wrap(*a, **kw):
         (code, data) = func(*a, **kw)
         json_data = json.dumps(data)
--- a/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
+++ b/testing/mozbase/mozhttpd/mozhttpd/mozhttpd.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import BaseHTTPServer
 import SimpleHTTPServer
 import errno
 import logging
 import threading
 import posixpath
 import socket
 import sys
@@ -318,14 +320,14 @@ def main(args=sys.argv[1:]):
     if options.external_ip:
         host = moznetwork.get_lan_ip()
     else:
         host = options.host
 
     # 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__':
     main()
--- a/testing/mozbase/mozhttpd/setup.py
+++ b/testing/mozbase/mozhttpd/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_VERSION = '0.7'
 deps = ['moznetwork >= 0.24']
 
 setup(name='mozhttpd',
       version=PACKAGE_VERSION,
--- a/testing/mozbase/mozhttpd/tests/api.py
+++ b/testing/mozbase/mozhttpd/tests/api.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import mozhttpd
 import urllib2
 import os
 import unittest
 import json
 import tempfile
 
--- a/testing/mozbase/mozhttpd/tests/baseurl.py
+++ b/testing/mozbase/mozhttpd/tests/baseurl.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import mozhttpd
 import unittest
 
 import mozunit
 
 
 class BaseUrlTest(unittest.TestCase):
 
--- a/testing/mozbase/mozhttpd/tests/basic.py
+++ b/testing/mozbase/mozhttpd/tests/basic.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import mozhttpd
 import mozfile
 import os
 import tempfile
 import unittest
 
 import mozunit
 
--- a/testing/mozbase/mozhttpd/tests/filelisting.py
+++ b/testing/mozbase/mozhttpd/tests/filelisting.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozhttpd
 import urllib2
 import os
 import unittest
 import re
 
 import mozunit
 
--- a/testing/mozbase/mozhttpd/tests/paths.py
+++ b/testing/mozbase/mozhttpd/tests/paths.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 
 # Any copyright is dedicated to the Public Domain.
 # http://creativecommons.org/publicdomain/zero/1.0/
 
+from __future__ import absolute_import
+
 from mozfile import TemporaryDirectory
 import mozhttpd
 import os
 import unittest
 import urllib2
 
 import mozunit
 
--- a/testing/mozbase/mozhttpd/tests/requestlog.py
+++ b/testing/mozbase/mozhttpd/tests/requestlog.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozhttpd
 import urllib2
 import os
 import unittest
 
 import mozunit
 
 here = os.path.dirname(os.path.abspath(__file__))
--- a/testing/mozbase/mozinfo/mozinfo/__init__.py
+++ b/testing/mozbase/mozinfo/mozinfo/__init__.py
@@ -53,8 +53,9 @@ Module variables:
    * :attr:`version`
 
 """
 
 from . import mozinfo
 from .mozinfo import *
 
 __all__ = mozinfo.__all__
+
--- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py
+++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
@@ -3,17 +3,17 @@
 # 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/.
 
 # TODO: it might be a good idea of adding a system name (e.g. 'Ubuntu' for
 # linux) to the information; I certainly wouldn't want anyone parsing this
 # information and having behaviour depend on it
 
-from __future__ import absolute_import
+from __future__ import absolute_import, print_function
 
 import os
 import platform
 import re
 import sys
 from .string_version import StringVersion
 from ctypes.util import find_library
 
@@ -287,21 +287,21 @@ def main(args=None):
             else:
                 string = arg
             update(json.loads(string))
 
     # print out choices if requested
     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()
--- a/testing/mozbase/mozinfo/mozinfo/string_version.py
+++ b/testing/mozbase/mozinfo/mozinfo/string_version.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from distutils.version import LooseVersion
 
 
 class StringVersion(str):
     """
     A string version that can be compared with comparison operators.
     """
 
--- a/testing/mozbase/mozinfo/setup.py
+++ b/testing/mozbase/mozinfo/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_VERSION = '0.10'
 
 # dependencies
 deps = ['mozfile >= 0.12']
 
--- a/testing/mozbase/mozinfo/tests/test.py
+++ b/testing/mozbase/mozinfo/tests/test.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import json
 import mock
 import os
 import shutil
 import sys
 import tempfile
 import unittest
 import mozinfo
--- a/testing/mozbase/mozinstall/mozinstall/__init__.py
+++ b/testing/mozbase/mozinstall/mozinstall/__init__.py
@@ -1,6 +1,8 @@
 # flake8: noqa
 # 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 mozinstall import *
+from __future__ import absolute_import
+
+from .mozinstall import *
\ No newline at end of file
--- a/testing/mozbase/mozinstall/mozinstall/mozinstall.py
+++ b/testing/mozbase/mozinstall/mozinstall/mozinstall.py
@@ -1,24 +1,28 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 from optparse import OptionParser
 import os
 import shutil
 import subprocess
 import sys
 import tarfile
 import tempfile
 import time
 import zipfile
 
 import requests
 
+from six import reraise
+
 import mozfile
 import mozinfo
 
 try:
     import pefile
     has_pefile = True
 except ImportError:
     has_pefile = False
@@ -103,17 +107,17 @@ def install(src, dest):
     if not is_installer(src):
         msg = "{} is not a valid installer file".format(src)
         if '://' in src:
             try:
                 return _install_url(src, dest)
             except:
                 exc, val, tb = sys.exc_info()
                 msg = "{} ({})".format(msg, val)
-                raise InvalidSource, msg, tb
+                reraise(InvalidSource, msg, tb)
         raise InvalidSource(msg)
 
     src = os.path.realpath(src)
     dest = os.path.realpath(dest)
 
     did_we_create = False
     if not os.path.exists(dest):
         did_we_create = True
@@ -141,19 +145,19 @@ def install(src, dest):
                 # uninstall may fail, let's just try to clean the folder
                 # in this case
                 try:
                     mozfile.remove(dest)
                 except:
                     pass
         if issubclass(cls, Exception):
             error = InstallError('Failed to install "%s (%s)"' % (src, str(exc)))
-            raise InstallError, error, trbk
+            reraise(InstallError, error, trbk)
         # any other kind of exception like KeyboardInterrupt is just re-raised.
-        raise cls, exc, trbk
+        reraise(cls, exc, trbk)
 
     finally:
         # trbk won't get GC'ed due to circular reference
         # http://docs.python.org/library/sys.html#sys.exc_info
         del trbk
 
 
 def is_installer(src):
@@ -208,41 +212,41 @@ def uninstall(install_folder):
     """
     install_folder = os.path.realpath(install_folder)
     assert os.path.isdir(install_folder), \
         'installation folder "%s" exists.' % install_folder
 
     # On Windows we have to use the uninstaller. If it's not available fallback
     # to the directory removal code
     if mozinfo.isWin:
-        uninstall_folder = '%s\uninstall' % install_folder
-        log_file = '%s\uninstall.log' % uninstall_folder
+        uninstall_folder = '%s\\uninstall' % install_folder
+        log_file = '%s\\uninstall.log' % uninstall_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.')
 
                 # The uninstaller spawns another process so the subprocess call
                 # returns immediately. We have to wait until the uninstall
                 # folder has been removed or until we run into a timeout.
                 end_time = time.time() + TIMEOUT_UNINSTALL
                 while os.path.exists(uninstall_folder):
                     time.sleep(1)
 
                     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
+                reraise(UninstallError, error, trbk)
 
             finally:
                 # trbk won't get GC'ed due to circular reference
                 # http://docs.python.org/library/sys.html#sys.exc_info
                 del trbk
 
     # Ensure that we remove any trace of the installation. Even the uninstaller
     # on Windows leaves files behind we have to explicitely remove.
@@ -357,17 +361,17 @@ def install_cli(argv=sys.argv[1:]):
 
     # Run it
     if os.path.isdir(src):
         binary = get_binary(src, app_name=options.app)
     else:
         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:]):
     parser = OptionParser(usage="usage: %prog install_path")
 
     (options, args) = parser.parse_args(argv)
     if not len(args) == 1:
         parser.error('An installation path has to be specified.')
--- a/testing/mozbase/mozinstall/setup.py
+++ b/testing/mozbase/mozinstall/setup.py
@@ -1,27 +1,29 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 import os
 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 = None
 
-PACKAGE_VERSION = '1.13'
+PACKAGE_VERSION = '1.14'
 
 deps = ['mozinfo >= 0.7',
         'mozfile >= 1.0',
         'requests',
+        'six >= 1.10.0',
         ]
 
 setup(name='mozInstall',
       version=PACKAGE_VERSION,
       description="package for installing and uninstalling Mozilla applications",
       long_description="see http://mozbase.readthedocs.org/",
       # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
       classifiers=['Environment :: Console',
--- a/testing/mozbase/mozinstall/tests/test.py
+++ b/testing/mozbase/mozinstall/tests/test.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import mozinfo
 import mozinstall
 import mozfile
 import os
 import tempfile
 import unittest
 
 import mozunit
--- a/testing/mozbase/mozleak/mozleak/__init__.py
+++ b/testing/mozbase/mozleak/mozleak/__init__.py
@@ -1,11 +1,13 @@
 # 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/.
 
 """
 mozleak is a library for extracting memory leaks from leak logs files.
 """
 
+from __future__ import absolute_import
+
 from .leaklog import process_leak_log
 
 __all__ = ['process_leak_log']
--- a/testing/mozbase/mozleak/mozleak/leaklog.py
+++ b/testing/mozbase/mozleak/mozleak/leaklog.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 import os
 import re
 
 
 def _get_default_logger():
     from mozlog import get_default_logger
     log = get_default_logger(component='mozleak')
--- a/testing/mozbase/mozleak/setup.py
+++ b/testing/mozbase/mozleak/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 
 PACKAGE_NAME = 'mozleak'
 PACKAGE_VERSION = '0.1'
 
 
--- a/testing/mozbase/mozlog/mozlog/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/__init__.py
@@ -8,16 +8,18 @@ Mozlog aims to standardize log handling 
 It implements a JSON-based structured logging protocol with convenience
 facilities for recording test results.
 
 The old unstructured module is deprecated. It simply wraps Python's
 logging_ module and adds a few convenience methods for logging test
 results and events.
 """
 
+from __future__ import absolute_import
+
 import sys
 
 from . import commandline
 from . import structuredlog
 from . import unstructured
 from .structuredlog import get_default_logger, set_default_logger
 from .proxy import get_proxy_logger
 
--- a/testing/mozbase/mozlog/mozlog/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/commandline.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import argparse
 import optparse
 import os
 import sys
 from collections import defaultdict
 
 from . import handlers
 from . import formatters
--- a/testing/mozbase/mozlog/mozlog/formatters/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/__init__.py
@@ -1,18 +1,20 @@
 # 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 unittest import UnittestFormatter
-from xunit import XUnitFormatter
-from html import HTMLFormatter
-from machformatter import MachFormatter
-from tbplformatter import TbplFormatter
-from errorsummary import ErrorSummaryFormatter
+from __future__ import absolute_import
+
+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
 except ImportError:
     import json
 
 
 def JSONFormatter():
--- a/testing/mozbase/mozlog/mozlog/formatters/base.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/base.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from ..reader import LogHandler
 
 
 class BaseFormatter(LogHandler):
     """Base class for implementing non-trivial formatters.
 
     Subclasses are expected to provide a method for each action type they
     wish to handle, each taking a single argument for the test data.
--- a/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/errorsummary.py
@@ -1,15 +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 __future__ import absolute_import
+
 import json
 
-from base import BaseFormatter
+from .base import BaseFormatter
 
 
 class ErrorSummaryFormatter(BaseFormatter):
 
     def __init__(self):
         self.groups = {}
         self.line_count = 0
 
--- a/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/__init__.py
@@ -1,3 +1,6 @@
-from html import HTMLFormatter
+
+from __future__ import absolute_import
+
+from .html import HTMLFormatter
 
 __all__ = ['HTMLFormatter']
--- a/testing/mozbase/mozlog/mozlog/formatters/html/html.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/html.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import base64
 import cgi
 from datetime import datetime
 import os
 
 from .. import base
 
 from collections import defaultdict
--- a/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/html/xmlgen.py
@@ -16,16 +16,19 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE F
 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.
 
 This file is originally from: https://bitbucket.org/hpk42/py, specifically:
 https://bitbucket.org/hpk42/py/src/980c8d526463958ee7cae678a7e4e9b054f36b94/py/_xmlgen.py?at=default
 by holger krekel, holger at merlinux eu. 2009
 """
+
+from __future__ import absolute_import
+
 import sys
 import re
 
 if sys.version_info >= (3, 0):
     def u(s):
         return s
 
     def unicode(x):
--- a/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/machformatter.py
@@ -1,21 +1,24 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+
+from __future__ import absolute_import
+
 import time
 from collections import defaultdict
 
 try:
     import blessings
 except ImportError:
     blessings = None
 
-import base
+from . import base
 from .process import strstatus
 
 
 def format_seconds(total):
     """Format number of seconds to MM:SS.DD form."""
     minutes, seconds = divmod(total, 60)
     return '%2d:%05.2f' % (minutes, seconds)
 
--- a/testing/mozbase/mozlog/mozlog/formatters/process.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/process.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import signal
 
 # a dict cache of signal number -> signal name
 _SIG_NAME = None
 
 
 def strsig(n):
--- a/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/tbplformatter.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import functools
 from collections import deque
 
 from .base import BaseFormatter
 from .process import strstatus
 
 
 def output_subtests(func):
--- a/testing/mozbase/mozlog/mozlog/formatters/unittest.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/unittest.py
@@ -1,14 +1,17 @@
 #!/usr/bin/env python
 # 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/.
 
-import base
+
+from __future__ import absolute_import
+
+from . import base
 
 
 class UnittestFormatter(base.BaseFormatter):
     """Formatter designed to produce output in a format like that used by
     the ``unittest`` module in the standard library."""
 
     def __init__(self):
         self.fails = []
--- a/testing/mozbase/mozlog/mozlog/formatters/xunit.py
+++ b/testing/mozbase/mozlog/mozlog/formatters/xunit.py
@@ -1,12 +1,14 @@
+from __future__ import absolute_import
+
 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:
         # Not sure how to deal with reftests yet
         raise NotImplementedError
--- a/testing/mozbase/mozlog/mozlog/handlers/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/__init__.py
@@ -1,11 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .base import LogLevelFilter, StreamHandler, BaseHandler
 from .statushandler import StatusHandler
 from .bufferhandler import BufferHandler
 from .valgrindhandler import ValgrindHandler
 
 __all__ = ['LogLevelFilter', 'StreamHandler', 'BaseHandler',
            'StatusHandler', 'BufferHandler', 'ValgrindHandler']
--- a/testing/mozbase/mozlog/mozlog/handlers/base.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/base.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from threading import Lock
 import codecs
 
 from ..structuredlog import log_levels
 
 
 class BaseHandler(object):
     """A base handler providing message handling facilities to
--- a/testing/mozbase/mozlog/mozlog/handlers/bufferhandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/bufferhandler.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .base import BaseHandler
 
 
 class BufferHandler(BaseHandler):
     """Handler that maintains a circular buffer of messages based on the
     size and actions specified by a user.
 
     :param inner: The underlying handler used to emit messages.
--- a/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/statushandler.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from collections import (
     defaultdict,
     namedtuple,
 )
 
 
 RunSummary = namedtuple("RunSummary",
                         ("unexpected_statuses",
--- a/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
+++ b/testing/mozbase/mozlog/mozlog/handlers/valgrindhandler.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .base import BaseHandler
 import re
 
 
 class ValgrindHandler(BaseHandler):
 
     def __init__(self, inner):
         BaseHandler.__init__(self, inner)
--- a/testing/mozbase/mozlog/mozlog/logtypes.py
+++ b/testing/mozbase/mozlog/mozlog/logtypes.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import inspect
 
 convertor_registry = {}
 missing = object()
 no_default = object()
 
 
 class log_action(object):
--- a/testing/mozbase/mozlog/mozlog/proxy.py
+++ b/testing/mozbase/mozlog/mozlog/proxy.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from multiprocessing import Queue
 from threading import Thread
 
 from .structuredlog import get_default_logger, StructuredLogger
 
 
 class ProxyLogger(object):
     """
--- a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
+++ b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozlog
 import time
 
 import pytest
 
 
 def pytest_addoption(parser):
     # We can't simply use mozlog.commandline.add_logging_group(parser) here because
--- a/testing/mozbase/mozlog/mozlog/reader.py
+++ b/testing/mozbase/mozlog/mozlog/reader.py
@@ -1,11 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import
+
 import json
 
 
 def read(log_f, raise_on_error=False):
     """Return a generator that will return the entries in a structured log file.
     Note that the caller must not close the file whilst the generator is still
     in use.
 
--- a/testing/mozbase/mozlog/mozlog/scripts/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/__init__.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import argparse
 import unstable
 import format as formatlog
 import logmerge
 
 
 def get_parser():
     parser = argparse.ArgumentParser("structlog",
--- a/testing/mozbase/mozlog/mozlog/scripts/format.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/format.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import argparse
 import sys
 
 from .. import handlers, commandline, reader
 
 
 def get_parser(add_help=True):
     parser = argparse.ArgumentParser("format",
--- a/testing/mozbase/mozlog/mozlog/scripts/logmerge.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/logmerge.py
@@ -1,9 +1,11 @@
-from __future__ import print_function
+
+from __future__ import absolute_import, print_function
+
 import argparse
 import json
 import os
 import sys
 from threading import current_thread
 import time
 from mozlog.reader import read
 
--- a/testing/mozbase/mozlog/mozlog/scripts/unstable.py
+++ b/testing/mozbase/mozlog/mozlog/scripts/unstable.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import, print_function
+
 import argparse
 from collections import defaultdict
 import json
 
 from mozlog import reader
 
 
 class StatusHandler(reader.LogHandler):
@@ -69,28 +71,28 @@ def group_results(data):
                 for status, number in results.iteritems():
                     rv[test][name][status] += number
     return rv
 
 
 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 "",
-                                " ".join("%s (%i)" % (k, v) for k, v in results.iteritems()))
+            print("[%s]: %s" % (name if name is not None else "",
+                                " ".join("%s (%i)" % (k, v) for k, v in results.iteritems())))
 
 
 def get_parser(add_help=True):
     parser = argparse.ArgumentParser("unstable",
                                      description="List tests that don't give consistent "
                                      "results from one or more runs.", add_help=add_help)
     parser.add_argument("--json", action="store_true", default=False,
                         help="Output in JSON format")
@@ -102,17 +104,17 @@ def get_parser(add_help=True):
 
 
 def main(**kwargs):
     unstable = filter_unstable(get_statuses(kwargs["log_file"]))
     if kwargs["group"]:
         unstable = group_results(unstable)
 
     if kwargs["json"]:
-        print json.dumps(unstable)
+        print(json.dumps(unstable))
     else:
         if not kwargs["group"]:
             print_results(unstable)
         else:
             print_run(unstable)
 
 
 if __name__ == "__main__":
--- a/testing/mozbase/mozlog/mozlog/stdadapter.py
+++ b/testing/mozbase/mozlog/mozlog/stdadapter.py
@@ -1,11 +1,13 @@
+from __future__ import absolute_import
+
 import logging
 
-from structuredlog import StructuredLogger, log_levels
+from .structuredlog import StructuredLogger, log_levels
 
 
 class UnstructuredHandler(logging.Handler):
 
     def __init__(self, name=None, level=logging.NOTSET):
         self.structured = StructuredLogger(name)
         logging.Handler.__init__(self, level=level)
 
--- a/testing/mozbase/mozlog/mozlog/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structuredlog.py
@@ -1,23 +1,23 @@
 # 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 __future__ import absolute_import, print_function, unicode_literals
 
 from multiprocessing import current_process
 from threading import current_thread, Lock
 import json
 import sys
 import time
 import traceback
 
-from logtypes import Unicode, TestId, TestList, Status, SubStatus, Dict, List, Int, Any, Tuple
-from logtypes import log_action, convertor_registry
+from .logtypes import Unicode, TestId, TestList, Status, SubStatus, Dict, List, Int, Any, Tuple
+from .logtypes import log_action, convertor_registry
 
 """Structured Logging for recording test results.
 
 Allowed actions, and subfields:
   suite_start
       tests  - List of test names
 
   suite_end
@@ -233,18 +233,18 @@ class StructuredLogger(object):
                     return
 
             for handler in self.handlers:
                 try:
                     handler(data)
                 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,
                     "time": int(time.time() * 1000),
                     "thread": current_thread().name,
                     "pid": current_process().pid,
                     "source": self.name}
         if self.component:
--- a/testing/mozbase/mozlog/mozlog/unstructured/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/__init__.py
@@ -1,8 +1,10 @@
 # flake8: noqa
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .logger import *
 from .loglistener import LogMessageServer
 from .loggingmixin import LoggingMixin
--- a/testing/mozbase/mozlog/mozlog/unstructured/logger.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/logger.py
@@ -1,13 +1,15 @@
 # flake8: noqa
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from logging import getLogger as getSysLogger
 from logging import *
 # Some of the build slave environments don't see the following when doing
 # 'from logging import *'
 # see https://bugzilla.mozilla.org/show_bug.cgi?id=700415#c35
 from logging import getLoggerClass, addLevelName, setLoggerClass, shutdown, debug, info, basicConfig
 import json
 
--- a/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/loggingmixin.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .logger import (
     Logger,
     getLogger,
 )
 
 
 class LoggingMixin(object):
     """Expose a subset of logging functions to an inheriting class."""
--- a/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
+++ b/testing/mozbase/mozlog/mozlog/unstructured/loglistener.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import SocketServer
 import socket
 import json
 
 
 class LogMessageServer(SocketServer.TCPServer):
 
     def __init__(self, server_address, logger, message_callback=None, timeout=3):
--- a/testing/mozbase/mozlog/setup.py
+++ b/testing/mozbase/mozlog/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup, find_packages
 
 PACKAGE_NAME = 'mozlog'
 PACKAGE_VERSION = '3.5'
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
--- a/testing/mozbase/mozlog/tests/test_logger.py
+++ b/testing/mozbase/mozlog/tests/test_logger.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import datetime
 import json
 import socket
 import threading
 import time
 import unittest
 
 import mozunit
--- a/testing/mozbase/mozlog/tests/test_logtypes.py
+++ b/testing/mozbase/mozlog/tests/test_logtypes.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import unittest
 import mozunit
 
 from mozlog.logtypes import (
     Any,
     Dict,
     Int,
     List,
--- a/testing/mozbase/mozlog/tests/test_structured.py
+++ b/testing/mozbase/mozlog/tests/test_structured.py
@@ -1,9 +1,12 @@
 # -*- coding: utf-8 -*-
+
+from __future__ import absolute_import
+
 import argparse
 import json
 import optparse
 import os
 import StringIO
 import sys
 import unittest
 import signal
--- a/testing/mozbase/moznetwork/moznetwork/__init__.py
+++ b/testing/mozbase/moznetwork/moznetwork/__init__.py
@@ -16,11 +16,13 @@ Example usage:
       ip = moznetwork.get_ip()
       print "The external IP of your machine is '%s'" % ip
   except moznetwork.NetworkError:
       print "Unable to determine IP address of machine"
       raise
 
 """
 
-from moznetwork import get_ip
+from __future__ import absolute_import
+
+from .moznetwork import get_ip
 
 __all__ = ['get_ip']
--- a/testing/mozbase/moznetwork/moznetwork/moznetwork.py
+++ b/testing/mozbase/moznetwork/moznetwork/moznetwork.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import argparse
 import array
 import re
 import socket
 import struct
 import subprocess
 import sys
 
--- a/testing/mozbase/moznetwork/setup.py
+++ b/testing/mozbase/moznetwork/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 PACKAGE_VERSION = '0.27'
 
 deps = ['mozinfo',
         'mozlog >= 3.0',
         ]
--- a/testing/mozbase/moznetwork/tests/test.py
+++ b/testing/mozbase/moznetwork/tests/test.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 """
 Unit-Tests for moznetwork
 """
 
+from __future__ import absolute_import
+
 import mock
 import mozinfo
 import moznetwork
 import re
 import subprocess
 import unittest
 from distutils.spawn import find_executable
 
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -1,13 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
-from __future__ import absolute_import
+from __future__ import absolute_import, print_function
 
 import errno
 import os
 import signal
 import subprocess
 import sys
 import threading
 import time
@@ -108,17 +108,17 @@ class ProcessHandlerMixin(object):
 
             try:
                 subprocess.Popen.__init__(self, args, bufsize, executable,
                                           stdin, stdout, stderr,
                                           preexec_fn, close_fds,
                                           shell, cwd, env,
                                           universal_newlines, startupinfo, creationflags)
             except OSError:
-                print >> sys.stderr, args
+                print(args, file=sys.stderr)
                 raise
 
         def debug(self, msg):
             if not MOZPROCESS_DEBUG:
                 return
             thread = threading.current_thread().name
             print("DBG::MOZPROC PID:{} ({}) | {}".format(self.pid, thread, msg))
 
@@ -169,17 +169,18 @@ class ProcessHandlerMixin(object):
                                     os.waitpid(-pid, 0)
                                 finally:
                                     return send_sig(sig, retries + 1)
 
                             # ESRCH is a "no such process" failure, which is fine because the
                             # application might already have been terminated itself. Any other
                             # error would indicate a problem in killing the process.
                             if getattr(e, "errno", None) != errno.ESRCH:
-                                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)
 
                 if sig is None and isPosix:
                     # ask the process for termination and wait a bit
                     send_sig(signal.SIGTERM)
                     limit = time.time() + self.TIMEOUT_BEFORE_SIGKILL
@@ -264,28 +265,28 @@ class ProcessHandlerMixin(object):
                 # Determine if we can create a job or create nested jobs.
                 can_create_job = winprocess.CanCreateJobObject()
                 can_nest_jobs = self._can_nest_jobs()
 
                 # Ensure we write a warning message if we are falling back
                 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
                 creationflags |= winprocess.CREATE_UNICODE_ENVIRONMENT
                 if can_create_job:
                     creationflags |= winprocess.CREATE_BREAKAWAY_FROM_JOB
                 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(
                     executable, args,
                     None, None,  # No special security
                     1,  # Must inherit handles!
                     creationflags,
                     winprocess.EnvironmentBlock(env),
@@ -348,20 +349,20 @@ class ProcessHandlerMixin(object):
 
                         # It's overkill, but we use Queue to signal between threads
                         # because it handles errors more gracefully than event or condition.
                         self._process_events = Queue()
 
                         # 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:
                     self._job = None
 
                 winprocess.ResumeThread(int(ht))
                 if getattr(self, '_procmgrthread', None):
                     self._procmgrthread.start()
@@ -414,44 +415,43 @@ falling back to not using job objects fo
                     if countdowntokill != 0:
                         diff = datetime.now() - countdowntokill
                         # Arbitrarily wait 3 minutes for windows to get its act together
                         # Windows sometimes takes a small nap between notifying the
                         # IO Completion port and actually killing the children, and we
                         # 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'})
                             break
 
                     if not portstatus:
                         # Check to see what happened
                         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
 
                     if compkey.value == winprocess.COMPKEY_TERMINATE.value:
                         self.debug("compkeyterminate detected")
                         # Then we're done
                         break
 
@@ -542,21 +542,22 @@ falling back to not using job objects fo
                         return self.returncode
 
                     rc = None
                     if self._handle:
                         rc = winprocess.WaitForSingleObject(self._handle, -1)
 
                     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
                         rc = winprocess.GetLastError()
                         if rc:
                             raise WinError(rc)
 
                     self._cleanup()
@@ -624,34 +625,34 @@ falling back to not using job objects fo
                         # returncode attribute
                         if status > 255:
                             return status >> 8
                         return -status
                     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 self.returncode
 
                 else:
                     # For non-group wait, call base class
                     subprocess.Popen.wait(self)
                     return self.returncode
 
             def _cleanup(self):
                 pass
 
         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)
                 return self.returncode
 
             def _cleanup(self):
                 pass
 
@@ -850,18 +851,18 @@ falling back to not using job objects fo
                 if timeout and count > timeout:
                     return None
 
         self.returncode = self.proc.wait()
         return self.returncode
 
     # 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
     def pid(self):
         return self.proc.pid
 
     @classmethod
     def _getpgid(cls, pid):
@@ -885,20 +886,20 @@ falling back to not using job objects fo
         if not self.proc:
             return
 
         if isPosix:
             new_pgid = self._getpgid(new_pid)
 
             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):
 
     def __call__(self, *args, **kwargs):
         for e in self:
             e(*args, **kwargs)
 
--- a/testing/mozbase/mozprocess/mozprocess/winprocess.py
+++ b/testing/mozbase/mozprocess/mozprocess/winprocess.py
@@ -29,17 +29,17 @@
 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-from __future__ import absolute_import, unicode_literals
+from __future__ import absolute_import, unicode_literals, print_function
 
 import sys
 import subprocess
 
 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE, c_ulong
 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
 from .qijo import QueryInformationJobObject
 
@@ -448,38 +448,38 @@ def CanCreateJobObject():
             bool(limitflags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)
     else:
         return True
 
 # 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 = 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()
--- a/testing/mozbase/mozprocess/setup.py
+++ b/testing/mozbase/mozprocess/setup.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from setuptools import setup
 
 PACKAGE_VERSION = '0.25'
 
 setup(name='mozprocess',
       version=PACKAGE_VERSION,
       description="Mozilla-authored process handling",
       long_description='see http://mozbase.readthedocs.org/',
--- a/testing/mozbase/mozprocess/tests/infinite_loop.py
+++ b/testing/mozbase/mozprocess/tests/infinite_loop.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import threading
 import time
 import sys
 import signal
 
 if 'deadlock' in sys.argv:
     lock = threading.Lock()
 
--- a/testing/mozbase/mozprocess/tests/proccountfive.py
+++ b/testing/mozbase/mozprocess/tests/proccountfive.py
@@ -1,2 +1,4 @@
+from __future__ import absolute_import, print_function
+
 for i in range(0, 5):
-    print i
+    print(i)
--- a/testing/mozbase/mozprocess/tests/proclaunch.py
+++ b/testing/mozbase/mozprocess/tests/proclaunch.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import, print_function
+
 import argparse
 import collections
 import ConfigParser
 import multiprocessing
 import time
 
 ProcessNode = collections.namedtuple('ProcessNode', ['maxtime', 'children'])
 
@@ -154,32 +156,32 @@ class ProcessLauncher(object):
         :param proc_name: File name of the manifest as a string.
         :param level: Depth of the current process in the tree.
         """
         if proc_name not in self.children.keys():
             raise IOError("%s is not a valid process" % proc_name)
 
         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)
+                                                        self.UNIT_TIME))
 
         while self.children[proc_name].children:
             child = self.children[proc_name].children.pop()
 
             count, child_proc = child
             for i in range(count):
                 p = multiprocessing.Process(target=self._run, args=(child[1], level + 1))
                 p.start()
 
         self._launch(maxtime)
         if self.verbose:
-            print "%sFinished %s" % (" " * level, proc_name)
+            print("%sFinished %s" % (" " * level, proc_name))
 
     def _launch(self, running_time):
         """
         Create and launch a process and idles for the time specified by
         `running_time`
 
         :param running_time: Running time of the process in seconds.
         """
--- a/testing/mozbase/mozprocess/tests/procnonewline.py
+++ b/testing/mozbase/mozprocess/tests/procnonewline.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import, print_function
+
 import sys
-print "this is a newline"
+print("this is a newline")
 sys.stdout.write("this has NO newline")
--- a/testing/mozbase/mozprocess/tests/proctest.py
+++ b/testing/mozbase/mozprocess/tests/proctest.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import os
 import sys
 import unittest
 import psutil
 
 here = os.path.dirname(os.path.abspath(__file__))
 
 
--- a/testing/mozbase/mozprocess/tests/test_mozprocess.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import os
 import subprocess
 import sys
 import proctest
 
 import mozunit
 
 from mozprocess import processhandler
@@ -39,19 +41,19 @@ def make_proclaunch(aDir):
     # on windows anyway (to file?), let's just call out both targets explicitly.
     for command in [["make", "-C", "iniparser"],
                     ["make"]]:
         process = subprocess.Popen(command, stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE, cwd=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
     if not os.path.exists(exepath):
         raise AssertionError("proclaunch executable '%s' "
                              "does not exist (sys.platform=%s)" % (exepath, sys.platform))
     return exepath
 
@@ -107,17 +109,17 @@ class ProcTest(proctest.ProcTest):
 
     def test_commandline_overspecified(self):
         """Command line raises an exception when the arguments are specified ambiguously"""
         err = None
         try:
             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)
 
     def test_commandline_from_list(self):
         """Command line is reported correctly when command and arguments are specified in a list"""
         p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"],
                                           cwd=here)
@@ -125,17 +127,17 @@ class ProcTest(proctest.ProcTest):
 
     def test_commandline_over_specified(self):
         """Command line raises an exception when the arguments are specified ambiguously"""
         err = None
         try:
             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)
 
     def test_commandline_from_args(self):
         """Command line is reported correctly when arguments are specified in a dedicated list"""
         p = processhandler.ProcessHandler(self.proclaunch,
                                           args=["1", "2", "3"],
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_kill.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import time
 import unittest
 import proctest
 import signal
 
 import mozunit
 
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_kill_broad_wait.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_kill_broad_wait.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import time
 import proctest
 
 import mozunit
 
 from mozprocess import processhandler
 
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
@@ -1,11 +1,13 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
+from __future__ import absolute_import
+
 import os
 
 import mozunit
 
 import proctest
 from mozprocess import processhandler
 
 here = os.path.dirname(os.path.abspath(__file__))
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_output.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_output.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import io
 import os
 
 import mozunit
 
 import proctest
 from mozprocess import processhandler
 
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_params.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_params.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import unittest
 
 import mozunit
 
 from mozprocess import processhandler
 
 
 class ParamTests(unittest.TestCase):
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_poll.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_poll.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import signal
 
 import mozunit
 
 from mozprocess import processhandler
 
 import proctest
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_wait.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_wait.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import proctest
 import mozinfo
 
 import mozunit
 
 from mozprocess import processhandler
 
--- a/testing/mozbase/mozprocess/tests/test_process_reader.py
+++ b/testing/mozbase/mozprocess/tests/test_process_reader.py
@@ -1,8 +1,10 @@
+from __future__ import absolute_import
+
 import unittest
 import subprocess
 import sys
 
 import mozunit
 
 from mozprocess.processhandler import ProcessReader, StoreOutput
 
--- a/testing/mozbase/mozprofile/mozprofile/__init__.py
+++ b/testing/mozbase/mozprofile/mozprofile/__init__.py
@@ -6,15 +6,17 @@
 """
 To use mozprofile as an API you can import mozprofile.profile_ and/or the AddonManager_.
 
 ``mozprofile.profile`` features a generic ``Profile`` class.  In addition,
 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 __future__ import absolute_import
+
+from mozprofile.addons import *
+from mozprofile.cli import *
+from mozprofile.diff import *
+from mozprofile.permissions import *
+from mozprofile.prefs import *
+from mozprofile.profile import *
+from mozprofile.view import *
--- a/testing/mozbase/mozprofile/mozprofile/addons.py
+++ b/testing/mozbase/mozprofile/mozprofile/addons.py
@@ -1,21 +1,26 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import
+
 import json
 import os
+import sys
 import shutil
-import sys
 import tempfile
 import urllib2
 import zipfile
 import hashlib
 from xml.dom import minidom
 
+from six import reraise
+
 import mozfile
 from mozlog.unstructured import getLogger
 
 # 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
 AMO_API_VERSION = "1.5"
 _SALT = os.urandom(32).encode('hex')
 _TEMPORARY_ADDON_SUFFIX = "@temporary-addon"
@@ -310,17 +315,17 @@ class AddonManager(object):
                         manifest = f.read()
                 except IOError:
                     with open(os.path.join(addon_path, 'manifest.json')) as f:
                         manifest = json.loads(f.read())
                         is_webext = True
             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]
+            reraise(AddonFormatError(str(e)), None, sys.exc_info()[2])
 
         if is_webext:
             details['version'] = manifest['version']
             details['name'] = manifest['name']
             try:
                 details['id'] = manifest['applications']['gecko']['id']
             except KeyError:
                 details['id'] = cls._gen_iid(addon_path)
@@ -340,17 +345,17 @@ class AddonManager(object):
                     if entry in 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():
                         details.update({entry: get_text(node)})
             except Exception as e:
-                raise AddonFormatError(str(e)), None, sys.exc_info()[2]
+                reraise(AddonFormatError(str(e)), None, sys.exc_info()[2])
 
         # turn unpack into a true/false value
         if isinstance(details['unpack'], basestring):
             details['unpack'] = details['unpack'].lower() == 'true'
 
         # If no ID is set, the add-on is invalid
         if details.get('id') is None and not is_webext:
             raise AddonFormatError('Add-on id could not be found.')
--- a/testing/mozbase/mozprofile/mozprofile/cli.py
+++ b/testing/mozbase/mozprofile/mozprofile/cli.py
@@ -5,22 +5,23 @@
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """
 Creates and/or modifies a Firefox profile.
 The profile can be modified by passing in addons to install or preferences to set.
 If no profile is specified, a new profile is created and the path of the
 resulting profile is printed.
 """
+from __future__ import absolute_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']
 
 
 class MozProfileCLI(object):
     """The Command Line Interface for ``mozprofile``."""
 
     module = 'mozprofile'
@@ -115,18 +116,18 @@ def cli(args=sys.argv[1:]):
     if cli.options.firefox_profile:
         cli.profile_class = FirefoxProfile
 
     # create the profile
     profile = cli.profile()
 
     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()
--- a/testing/mozbase/mozprofile/mozprofile/diff.py
+++ b/testing/mozbase/mozprofile/mozprofile/diff.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 """
 diff two profile summaries
 """
 
+from __future__ import absolute_import, print_function
+
 import difflib
 import profile
 import optparse
 import os
 import sys
 
 __all__ = ['diff', 'diff_profiles']
 
@@ -67,16 +69,16 @@ def diff_profiles(args=sys.argv[1:]):
 
     # get the profile differences
     diffs = diff(*([profile.Profile(arg)
                     for arg in args]))
 
     # 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()
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py
+++ b/testing/mozbase/mozprofile/mozprofile/permissions.py
@@ -2,16 +2,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/.
 
 
 """
 add permissions to the profile
 """
 
+from __future__ import absolute_import
+
 import codecs
 import os
 import sqlite3
 import urlparse
 
 __all__ = ['MissingPrimaryLocationError', 'MultiplePrimaryLocationsError',
            'DEFAULT_PORTS', 'DuplicateLocationError', 'BadPortLocationError',
            'LocationsSyntaxError', 'Location', 'ServerLocations',
--- a/testing/mozbase/mozprofile/mozprofile/prefs.py
+++ b/testing/mozbase/mozprofile/mozprofile/prefs.py
@@ -1,15 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """
 user preferences
 """
+from __future__ import absolute_import, print_function
 
 import json
 import mozfile
 import os
 import tokenize
 from ConfigParser import SafeConfigParser as ConfigParser
 from StringIO import StringIO
 
@@ -191,17 +192,17 @@ class Preferences(object):
         lines = [i.strip().rstrip(';') for i in string.split('\n') if i.strip()]
 
         _globals = {'retval': retval, 'true': True, 'false': False}
         _globals[pref_setter] = pref
         for line in lines:
             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:
                 retval[index] = (key, value.replace(marker, '//'))
 
         return retval
@@ -220,13 +221,13 @@ class Preferences(object):
             prefs = prefs.items()
 
         # serialize -> JSON
         _prefs = [(json.dumps(k), json.dumps(v))
                   for k, v in prefs]
 
         # 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):
             f.close()
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -1,22 +1,24 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import platform
 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
 
 __all__ = ['Profile',
            'FirefoxProfile',
            'ThunderbirdProfile']
 
 
 class Profile(object):
--- a/testing/mozbase/mozprofile/mozprofile/view.py
+++ b/testing/mozbase/mozprofile/mozprofile/view.py
@@ -1,13 +1,14 @@
 #!/usr/bin/env python
 
 """
 script to view mozilla profiles
 """
+from __future__ import absolute_import, print_function
 
 import mozprofile
 import optparse
 import os
 import sys
 
 __all__ = ['view_profile']
 
@@ -30,15 +31,15 @@ def view_profile(args=sys.argv[1:]):
         else:
             missing_string = "Profile does not exist"
         parser.error("%s: %s" % (missing_string, ', '.join(missing)))
 
     # print summary for each profile
     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()
--- a/testing/mozbase/mozprofile/setup.py
+++ b/testing/mozbase/mozprofile/setup.py
@@ -1,22 +1,27 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import sys
 from setuptools import setup
 
 PACKAGE_NAME = 'mozprofile'
-PACKAGE_VERSION = '0.28'
+PACKAGE_VERSION = '0.29'
 
 # we only support python 2 right now
 assert sys.version_info[0] == 2
 
-deps = ['mozfile >= 1.0', 'mozlog >= 3.0']
+deps = ['mozfile >= 1.0',
+        'mozlog >= 3.0',
+        'six >= 1.10.0'
+        ]
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Library to create and modify Mozilla application profiles",
       long_description="see http://mozbase.readthedocs.org/",
       classifiers=['Environment :: Console',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
--- a/testing/mozbase/mozprofile/tests/addon_stubs.py
+++ b/testing/mozbase/mozprofile/tests/addon_stubs.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import tempfile
 import zipfile
 
 import mozfile
 
 
 here = os.path.dirname(os.path.abspath(__file__))
--- a/testing/mozbase/mozprofile/tests/addonid.py
+++ b/testing/mozbase/mozprofile/tests/addonid.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import os
 import tempfile
 import unittest
 import shutil
 
 import mozunit
 
 from mozprofile import addons
--- a/testing/mozbase/mozprofile/tests/bug758250.py
+++ b/testing/mozbase/mozprofile/tests/bug758250.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import mozprofile
 import os
 import shutil
 import tempfile
 import unittest
 
 import mozunit
 
--- a/testing/mozbase/mozprofile/tests/bug785146.py
+++ b/testing/mozbase/mozprofile/tests/bug785146.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import os
 import shutil
 import sqlite3
 import tempfile
 import unittest
 
 import mozunit
--- a/testing/mozbase/mozprofile/tests/permissions.py
+++ b/testing/mozbase/mozprofile/tests/permissions.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import os
 import shutil
 import sqlite3
 import tempfile
 import unittest
 
 import mozunit
--- a/testing/mozbase/mozprofile/tests/server_locations.py
+++ b/testing/mozbase/mozprofile/tests/server_locations.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import unittest
 
 import mozunit
 
 from mozprofile.permissions import ServerLocations, \
     MissingPrimaryLocationError, MultiplePrimaryLocationsError, \
     DuplicateLocationError, BadPortLocationError, LocationsSyntaxError
--- a/testing/mozbase/mozprofile/tests/test_addons.py
+++ b/testing/mozbase/mozprofile/tests/test_addons.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import tempfile
 import unittest
 import urllib2
 import zipfile
 
 import mozunit
--- a/testing/mozbase/mozprofile/tests/test_clone_cleanup.py
+++ b/testing/mozbase/mozprofile/tests/test_clone_cleanup.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 import os
 import tempfile
 import unittest
 import mozfile
 
 import mozunit
 
--- a/testing/mozbase/mozprofile/tests/test_nonce.py
+++ b/testing/mozbase/mozprofile/tests/test_nonce.py
@@ -1,15 +1,17 @@
 #!/usr/bin/env python
 
 """
 test nonce in prefs delimeters
 see https://bugzilla.mozilla.org/show_bug.cgi?id=722804
 """
 
+from __future__ import absolute_import
+
 import os
 import tempfile
 import unittest
 import mozfile
 
 import mozunit
 
 from mozprofile.prefs import Preferences
--- a/testing/mozbase/mozprofile/tests/test_preferences.py
+++ b/testing/mozbase/mozprofile/tests/test_preferences.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import mozhttpd
 import os
 import shutil
 import tempfile
 import unittest
 
 import mozunit
--- a/testing/mozbase/mozprofile/tests/test_profile.py
+++ b/testing/mozbase/mozprofile/tests/test_profile.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import unittest
 import os
 
 import mozunit
 
 from mozprofile import Profile
 
 
--- a/testing/mozbase/mozprofile/tests/test_profile_view.py
+++ b/testing/mozbase/mozprofile/tests/test_profile_view.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import mozprofile
 import os
 import tempfile
 import unittest
 
 import mozunit
 
--- a/testing/mozbase/mozrunner/mozrunner/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/__init__.py
@@ -1,11 +1,14 @@
 # flake8: noqa
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from __future__ import absolute_import
+
 from .cli import *
 from .errors import *
 from .runners import *
 
-import base
-import devices
-import utils
+import mozrunner.base
+import mozrunner.devices
+import mozrunner.utils
--- a/testing/mozbase/mozrunner/mozrunner/application.py
+++ b/testing/mozbase/mozrunner/mozrunner/application.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from abc import ABCMeta, abstractmethod
 from distutils.spawn import find_executable
 import glob
 import os
 import posixpath
 
 from mozdevice import DeviceManagerADB, DMError, DroidADB
 from mozprofile import (
--- a/testing/mozbase/mozrunner/mozrunner/base/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/__init__.py
@@ -1,5 +1,7 @@
+from __future__ import absolute_import
+
 from .runner import BaseRunner
 from .device import DeviceRunner, FennecRunner
 from .browser import GeckoRuntimeRunner
 
 __all__ = ['BaseRunner', 'DeviceRunner', 'FennecRunner', 'GeckoRuntimeRunner']
--- a/testing/mozbase/mozrunner/mozrunner/base/browser.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozinfo
 import os
 import sys
 
 from .runner import BaseRunner
 
 
 class GeckoRuntimeRunner(BaseRunner):
--- a/testing/mozbase/mozrunner/mozrunner/base/device.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/device.py
@@ -1,13 +1,13 @@
 # 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 __future__ import absolute_import, print_function
 
 import datetime
 import re
 import signal
 import sys
 import tempfile
 import time
 
--- a/testing/mozbase/mozrunner/mozrunner/base/runner.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/runner.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from abc import ABCMeta, abstractproperty
 import os
 import subprocess
 import traceback
 import sys
 
 from mozlog import get_default_logger
 from mozprocess import ProcessHandler
--- a/testing/mozbase/mozrunner/mozrunner/cli.py
+++ b/testing/mozbase/mozrunner/mozrunner/cli.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import os
 import sys
 
 from mozprofile import MozProfileCLI
 
 from .application import get_app_context
 from .runners import runners
 from .utils import findInPath
@@ -132,17 +134,17 @@ class CLI(MozProfileCLI):
 
         It can also happen via a keyboard interrupt. It should be
         overwritten to provide custom running of the runner instance.
 
         """
         # 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:
             runner.stop()
 
 
 def cli(args=sys.argv[1:]):
     CLI(args).run()
--- a/testing/mozbase/mozrunner/mozrunner/devices/__init__.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/__init__.py
@@ -1,13 +1,15 @@
 # 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 emulator import BaseEmulator, Emulator, EmulatorAVD
-from base import Device
+from __future__ import absolute_import
 
-import emulator_battery
-import emulator_geo
-import emulator_screen
+from .emulator import BaseEmulator, Emulator, EmulatorAVD
+from .base import Device
+
+from mozrunner.devices import emulator_battery
+from mozrunner.devices import emulator_geo
+from mozrunner.devices import emulator_screen
 
 __all__ = ['BaseEmulator', 'Emulator', 'EmulatorAVD', 'Device',
            'emulator_battery', 'emulator_geo', 'emulator_screen']
--- a/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/android_device.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import fileinput
 import glob
 import os
 import platform
 import psutil
 import shutil
 import signal
 import sys
@@ -681,48 +683,48 @@ def _find_sdk_exe(substs, exe, tools):
                         break
     else:
         exe_path = None
     return exe_path
 
 
 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):
     _log_debug("Download %s to %s/%s..." % (url, path, filename))
     f = urllib2.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')
     local_file.write(f.read())
     local_file.close()
     _log_debug("Downloaded %s to %s/%s" % (url, path, filename))
     return True
 
 
 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:
         src = os.path.join(substs['top_srcdir'], src_path)
         if os.path.exists(src):
             dst = os.path.join(dst_path, filename)
             shutil.copy(src, dst)
             copied = True
--- a/testing/mozbase/mozrunner/mozrunner/devices/autophone.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/autophone.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import glob
 import json
 import logging
 import os
 import shutil
 import signal
 import socket
 import sys
--- a/testing/mozbase/mozrunner/mozrunner/devices/base.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/base.py
@@ -1,8 +1,11 @@
+from __future__ import absolute_import, print_function
+
+
 from ConfigParser import (
     ConfigParser,
     RawConfigParser
 )
 import datetime
 import os
 import posixpath
 import re
@@ -84,17 +87,17 @@ class Device(object):
 
         timeout = 5  # seconds
         starttime = datetime.datetime.now()
         while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
             if self.dm.fileExists(self.app_ctx.remote_profiles_ini):
                 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)
 
         config = ProfileConfigParser()
         config.read(local_profiles_ini.name)
         for section in config.sections():
             if 'Profile' in section:
@@ -170,17 +173,17 @@ class Device(object):
 
     def install_busybox(self, busybox):
         """
         Installs busybox on the device.
 
         :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.
         args = [self.app_ctx.adb, '-s', self.dm._deviceSerial,
                 'shell', 'cd /system/bin; chmod 555 busybox;'
                 'for x in `./busybox --list`; do ln -s ./busybox $x; done']
         adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         adb.wait()
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from telnetlib import Telnet
 import datetime
 import os
 import shutil
 import subprocess
 import tempfile
 import time
 
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_battery.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 class EmulatorBattery(object):
 
     def __init__(self, emulator):
         self.emulator = emulator
 
     def get_state(self):
         status = {}
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_geo.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 class EmulatorGeo(object):
 
     def __init__(self, emulator):
         self.emulator = emulator
 
     def set_default_location(self):
         self.lon = -122.08769
--- a/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
+++ b/testing/mozbase/mozrunner/mozrunner/devices/emulator_screen.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 class EmulatorScreen(object):
     """Class for screen related emulator commands."""
 
     SO_PORTRAIT_PRIMARY = 'portrait-primary'
     SO_PORTRAIT_SECONDARY = 'portrait-secondary'
     SO_LANDSCAPE_PRIMARY = 'landscape-primary'
     SO_LANDSCAPE_SECONDARY = 'landscape-secondary'
--- a/testing/mozbase/mozrunner/mozrunner/errors.py
+++ b/testing/mozbase/mozrunner/mozrunner/errors.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 class RunnerException(Exception):
     """Base exception handler for mozrunner related errors"""
 
 
 class RunnerNotStartedError(RunnerException):
     """Exception handler in case the runner hasn't been started"""
 
--- a/testing/mozbase/mozrunner/mozrunner/runners.py
+++ b/testing/mozbase/mozrunner/mozrunner/runners.py
@@ -1,17 +1,20 @@
 # 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/.
 
+
 """
 This module contains a set of shortcut methods that create runners for commonly
 used Mozilla applications, such as Firefox or B2G emulator.
 """
 
+from __future__ import absolute_import
+
 from .application import get_app_context
 from .base import DeviceRunner, GeckoRuntimeRunner, FennecRunner
 from .devices import Emulator, EmulatorAVD, Device
 
 
 def Runner(*args, **kwargs):
     """
     Create a generic GeckoRuntime runner.
--- a/testing/mozbase/mozrunner/mozrunner/utils.py
+++ b/testing/mozbase/mozrunner/mozrunner/utils.py
@@ -1,16 +1,18 @@
 #!/usr/bin/env python
 
 # 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/.
 
 """Utility functions for mozrunner"""
 
+from __future__ import absolute_import, print_function
+
 import mozinfo
 import os
 import sys
 
 __all__ = ['findInPath', 'get_metadata_from_egg']
 
 
 # python package method metadata by introspection
@@ -59,17 +61,17 @@ def findInPath(fileName, path=os.environ
             return os.path.join(dir, fileName)
         if mozinfo.isWin:
             if os.path.isfile(os.path.join(dir, fileName + ".exe")):
                 return os.path.join(dir, fileName + ".exe")
 
 
 if __name__ == '__main__':
     for i in sys.argv[1:]:
-        print findInPath(i)
+        print(findInPath(i))
 
 
 def _find_marionette_in_args(*args, **kwargs):
     try:
         m = [a for a in args + tuple(kwargs.values()) if hasattr(a, 'session')][0]
     except IndexError:
         print("Can only apply decorator to function using a marionette object")
         raise
--- a/testing/mozbase/mozrunner/setup.py
+++ b/testing/mozbase/mozrunner/setup.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import sys
 from setuptools import setup, find_packages
 
 PACKAGE_NAME = 'mozrunner'
 PACKAGE_VERSION = '6.13'
 
 desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
 
--- a/testing/mozbase/mozrunner/tests/mozrunnertest.py
+++ b/testing/mozbase/mozrunner/tests/mozrunnertest.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import unittest
 
 import mozprofile
 import mozrunner
 
 
 @unittest.skipIf(not os.environ.get('BROWSER_PATH'),
--- a/testing/mozbase/mozrunner/tests/test_crash.py
+++ b/testing/mozbase/mozrunner/tests/test_crash.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mock
 import mozunit
 
 import mozrunnertest
 
 
 class MozrunnerCrashTestCase(mozrunnertest.MozrunnerTestCase):
 
--- a/testing/mozbase/mozrunner/tests/test_interactive.py
+++ b/testing/mozbase/mozrunner/tests/test_interactive.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import threading
 from time import sleep
 
 import mozunit
 
 import mozrunnertest
 
 
--- a/testing/mozbase/mozrunner/tests/test_start.py
+++ b/testing/mozbase/mozrunner/tests/test_start.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 from time import sleep
 
 import mozunit
 
 import mozrunnertest
 
 
 class MozrunnerStartTestCase(mozrunnertest.MozrunnerTestCase):
--- a/testing/mozbase/mozrunner/tests/test_states.py
+++ b/testing/mozbase/mozrunner/tests/test_states.py
@@ -1,10 +1,12 @@
 #!/usr/bin/env python
 
+from __future__ import absolute_import
+
 import mozrunner
 
 import mozunit
 
 import mozrunnertest
 
 
 class MozrunnerStatesTestCase(mozrunnertest.MozrunnerTestCase):
--- a/testing/mozbase/mozrunner/tests/test_stop.py
+++ b/testing/mozbase/mozrunner/tests/test_stop.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import signal
 
 import mozunit
 
 import mozrunnertest
 
 
 class MozrunnerStopTestCase(mozrunnertest.MozrunnerTestCase):
--- a/testing/mozbase/mozrunner/tests/test_threads.py
+++ b/testing/mozbase/mozrunner/tests/test_threads.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import threading
 from time import sleep
 
 import mozunit
 
 import mozrunnertest
 
 
--- a/testing/mozbase/mozrunner/tests/test_wait.py
+++ b/testing/mozbase/mozrunner/tests/test_wait.py
@@ -1,13 +1,15 @@
 #!/usr/bin/env python
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozunit
 import mozrunnertest
 
 
 class MozrunnerWaitTestCase(mozrunnertest.MozrunnerTestCase):
 
     def test_wait_while_running(self):
         """Wait for the process while it is running"""
--- a/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
+++ b/testing/mozbase/mozscreenshot/mozscreenshot/__init__.py
@@ -1,27 +1,29 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, print_function
+
 import os
 import mozinfo
 import tempfile
 import subprocess
 from mozlog.formatters.process import strstatus
 
 
 def printstatus(name, returncode):
     """
     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):
     """dumps a screenshot of the entire screen to a directory specified by
     the MOZ_UPLOAD_DIR environment variable"""
 
     is_structured_log = hasattr(log, 'process_exit')
 
@@ -51,11 +53,11 @@ def dump_screen(utilityPath, log):
         os.close(tmpfd)
         if is_structured_log:
             log.process_start(utilityname)
         returncode = subprocess.call(utility + [imgfilename])
         if is_structured_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))
--- a/testing/mozbase/mozscreenshot/setup.py
+++ b/testing/mozbase/mozscreenshot/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup
 
 
 PACKAGE_NAME = 'mozscreenshot'
 PACKAGE_VERSION = '0.1'
 
 
--- a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
+++ b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from contextlib import contextmanager
 import multiprocessing
 import sys
 import time
 import warnings
 
 from collections import (
     OrderedDict,
--- a/testing/mozbase/mozsystemmonitor/setup.py
+++ b/testing/mozbase/mozsystemmonitor/setup.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 
 from setuptools import setup
 
 PACKAGE_VERSION = '0.3'
 
 try:
     pwd = os.path.dirname(os.path.abspath(__file__))
--- a/testing/mozbase/mozsystemmonitor/tests/test_resource_monitor.py
+++ b/testing/mozbase/mozsystemmonitor/tests/test_resource_monitor.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import multiprocessing
 import time
 import unittest
 
 import mozunit
 
 try:
     import psutil
--- a/testing/mozbase/moztest/moztest/__init__.py
+++ b/testing/mozbase/moztest/moztest/__init__.py
@@ -1,7 +1,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/.
 
-import adapters
+from __future__ import absolute_import
 
+from moztest import adapters
 __all__ = ['adapters']
--- a/testing/mozbase/moztest/moztest/adapters/__init__.py
+++ b/testing/mozbase/moztest/moztest/adapters/__init__.py
@@ -1,7 +1,9 @@
 # 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/.
 
-import unit
+from __future__ import absolute_import
+
+from moztest.adapters import unit
 
 __all__ = ['unit']
--- a/testing/mozbase/moztest/moztest/adapters/unit.py
+++ b/testing/mozbase/moztest/moztest/adapters/unit.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import unittest
 import sys
 import time
 import traceback
 
 try:
     from unittest import TextTestResult
 except ImportError:
--- a/testing/mozbase/moztest/moztest/output/autolog.py
+++ b/testing/mozbase/moztest/moztest/output/autolog.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 from mozautolog import RESTfulAutologTestGroup
 
 from base import Output, count, long_name
 
 
 class AutologOutput(Output):
 
--- a/testing/mozbase/moztest/moztest/output/base.py
+++ b/testing/mozbase/moztest/moztest/output/base.py
@@ -1,14 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import, with_statement
 
-from __future__ import with_statement
 from contextlib import closing
 from StringIO import StringIO
 
 try:
     from abc import abstractmethod
 except ImportError:
     # abc is python 2.6+
     # from https://github.com/mozilla/mozbase/blob/master/mozdevice/mozdevice/devicemanager.py
--- a/testing/mozbase/moztest/moztest/output/xunit.py
+++ b/testing/mozbase/moztest/moztest/output/xunit.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 import xml.dom.minidom as dom
 
 from base import Output, count
 from moztest.results import TestResult
 
 
 class XUnitOutput(Output):
--- a/testing/mozbase/moztest/moztest/results.py
+++ b/testing/mozbase/moztest/moztest/results.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 import time
 import os
 import mozinfo
 
 
 class TestContext(object):
     """ Stores context data about the test """
--- a/testing/mozbase/moztest/moztest/selftest/fixtures.py
+++ b/testing/mozbase/moztest/moztest/selftest/fixtures.py
@@ -1,15 +1,17 @@
 # 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/.
 """Pytest fixtures to help set up Firefox and a tests.zip
 in test harness selftests.
 """
 
+from __future__ import absolute_import
+
 import os
 import shutil
 import sys
 
 import mozfile
 import mozinstall
 import pytest
 import requests
--- a/testing/mozbase/moztest/moztest/selftest/output.py
+++ b/testing/mozbase/moztest/moztest/selftest/output.py
@@ -1,14 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """Methods for testing interactions with mozharness."""
 
+from __future__ import absolute_import
+
 import json
 import os
 import sys
 
 from mozbuild.base import MozbuildObject
 
 here = os.path.abspath(os.path.dirname(__file__))
 build = MozbuildObject.from_environment(cwd=here)
--- a/testing/mozbase/moztest/setup.py
+++ b/testing/mozbase/moztest/setup.py
@@ -1,12 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
 
 from setuptools import setup, find_packages
 
 PACKAGE_VERSION = '0.8'
 
 # dependencies
 deps = ['mozinfo']
 
--- a/testing/mozbase/moztest/tests/test.py
+++ b/testing/mozbase/moztest/tests/test.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import math
 import time
 import unittest
 
 import mozunit
 
 from moztest.results import TestContext, TestResult, TestResultCollection
 
--- a/testing/mozbase/mozversion/mozversion/__init__.py
+++ b/testing/mozbase/mozversion/mozversion/__init__.py
@@ -1,7 +1,12 @@
 # flake8: noqa
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from .errors import *
+
+import mozversion.errors
+
 from .mozversion import cli, get_version
--- a/testing/mozbase/mozversion/mozversion/errors.py
+++ b/testing/mozbase/mozversion/mozversion/errors.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 
 class VersionError(Exception):
 
     def __init__(self, message):
         Exception.__init__(self, message)
 
 
 class AppNotFoundError(VersionError):
--- a/testing/mozbase/mozversion/mozversion/mozversion.py
+++ b/testing/mozbase/mozversion/mozversion/mozversion.py
@@ -1,26 +1,28 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import argparse
 import ConfigParser
 from StringIO import StringIO
 import os
 import re
 import sys
 import tempfile
 import xml.dom.minidom
 import zipfile
 
 import mozfile
 import mozlog
 
-import errors
+from mozversion import errors
 
 
 INI_DATA_MAPPING = (('application', 'App'), ('platform', 'Build'))
 
 
 class Version(object):
 
     def __init__(self):
@@ -94,16 +96,17 @@ class LocalVersion(Version):
         if not self.check_location(path):
             if sys.platform == 'darwin':
                 resources_path = os.path.join(os.path.dirname(path),
                                               'Resources')
                 if self.check_location(resources_path):
                     path = resources_path
                 else:
                     raise errors.LocalAppNotFoundError(path)
+
             else:
                 raise errors.LocalAppNotFoundError(path)
 
         self.get_gecko_info(path)
 
     def check_location(self, path):
         return (os.path.exists(os.path.join(path, 'application.ini'))
                 and os.path.exists(os.path.join(path, 'platform.ini')))
--- a/testing/mozbase/mozversion/setup.py
+++ b/testing/mozbase/mozversion/setup.py
@@ -1,12 +1,14 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 from setuptools import setup
 
 PACKAGE_VERSION = '1.4'
 
 
 setup(name='mozversion',
       version=PACKAGE_VERSION,
       description='Library to get version information for applications',
--- a/testing/mozbase/mozversion/tests/test_apk.py
+++ b/testing/mozbase/mozversion/tests/test_apk.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import mozfile
 import unittest
 import zipfile
 
 import mozunit
 
 from mozversion import get_version
 
--- a/testing/mozbase/mozversion/tests/test_b2g.py
+++ b/testing/mozbase/mozversion/tests/test_b2g.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import tempfile
 import unittest
 import zipfile
 
 import mozunit
 
 import mozfile
--- a/testing/mozbase/mozversion/tests/test_binary.py
+++ b/testing/mozbase/mozversion/tests/test_binary.py
@@ -1,23 +1,26 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import sys
 import tempfile
 import shutil
 import unittest
 
 import mozunit
 
 import mozfile
+
 from mozversion import errors, get_version
 
 
 class BinaryTest(unittest.TestCase):
     """test getting application version information from a binary path"""
 
     application_ini = """[App]
 ID = AppID
--- a/testing/mozbase/mozversion/tests/test_sources.py
+++ b/testing/mozbase/mozversion/tests/test_sources.py
@@ -1,14 +1,16 @@
 #!/usr/bin/env python
 
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
+from __future__ import absolute_import
+
 import os
 import tempfile
 import unittest
 
 import mozunit
 
 import mozfile
 from mozversion import errors, get_version
--- a/testing/mozbase/setup_development.py
+++ b/testing/mozbase/setup_development.py
@@ -8,16 +8,18 @@
 Setup mozbase packages for development.
 
 Packages may be specified as command line arguments.
 If no arguments are given, install all packages.
 
 See https://wiki.mozilla.org/Auto-tools/Projects/Mozbase
 """
 
+from __future__ import absolute_import, print_function
+
 import os
 import subprocess
 import sys
 from optparse import OptionParser
 from subprocess import PIPE
 try:
     from subprocess import check_call as call
 except ImportError:
@@ -52,17 +54,17 @@ def info(directory):
 
     assert os.path.exists(os.path.join(directory, 'setup.py'))
 
     # setup the egg info
     try:
         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
     egg_info = [entry for entry in os.listdir(directory)
                 if entry.endswith('.egg-info')]
     assert len(egg_info) == 1, 'Expected one .egg-info directory in %s, got: %s' % (directory,
                                                                                     egg_info)
     egg_info = os.path.join(directory, egg_info[0])
@@ -175,17 +177,17 @@ def main(args=sys.argv[1:]):
 
     # ensure specified packages are in the list
     assert set(packages).issubset(mozbase_packages), \
         "Packages should be in %s (You gave: %s)" % (mozbase_packages, packages)
 
     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
     # TODO: version conflict checking
     deps = {}
     alldeps = {}
     mapping = {}  # mapping from subdir name to package name
     # core dependencies
@@ -230,17 +232,17 @@ def main(args=sys.argv[1:]):
     reverse_mapping = dict([(j, i) for i, j in mapping.items()])
 
     # we only care about dependencies in mozbase
     unrolled = [package for package in unrolled if package in reverse_mapping]
 
     if options.list:
         # list what will be installed
         for package in unrolled:
-            print package
+            print(package)
         parser.exit()
 
     # set up the packages for development
     for package in unrolled:
         call([sys.executable, 'setup.py', 'develop', '--no-deps'],
              cwd=os.path.join(here, reverse_mapping[package]))
 
     # add the directory of sys.executable to path to aid the correct
--- a/testing/mozbase/versioninfo.py
+++ b/testing/mozbase/versioninfo.py
@@ -4,16 +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/.
 
 """
 List mozbase package dependencies or generate changelogs
 from commit messages.
 """
 
+from __future__ import absolute_import, print_function
+
 from collections import Iterable
 from distutils.version import StrictVersion
 import argparse
 import os
 import subprocess
 import sys
 
 import setup_development
@@ -79,34 +81,34 @@ def changelog(args):
                         '-M', args.module]).split(delim)[:-1]
 
     def prettify(desc):
         lines = desc.splitlines()
         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)
+    print('\n'.join(changelog))
 
 
 def dependencies(args):
     # get package information
     info = {}
     dependencies = {}
     for package in setup_development.mozbase_packages:
         directory = os.path.join(setup_development.here, package)
         info[directory] = setup_development.info(directory)
         name, _dependencies = setup_development.get_dependencies(directory)
         assert name == info[directory]['Name']
         dependencies[name] = _dependencies
 
     # 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:]):
     parser = argparse.ArgumentParser()
     subcommands = parser.add_subparsers(help="Sub-commands")
 
     p_deps = subcommands.add_parser('dependencies', help="Print dependencies.")
     p_deps.set_defaults(func=dependencies)
--- a/tools/lint/py2.yml
+++ b/tools/lint/py2.yml
@@ -36,17 +36,16 @@ py2:
         - servo
         - testing/awsy
         - testing/firefox-ui
         - testing/geckodriver
         - testing/gtest
         - testing/instrumentation/runinstrumentation.py
         - testing/marionette
         - testing/mochitest
-        - testing/mozbase
         - testing/mozharness
         - testing/remotecppunittests.py
         - testing/runcppunittests.py
         - testing/runtimes
         - testing/tools
         - testing/tps
         - testing/web-platform
         - third_party
--- a/tools/lint/py3.yml
+++ b/tools/lint/py3.yml
@@ -28,17 +28,16 @@ py3:
         - security/nss
         - services/common/tests/mach_commands.py
         - servo
         - testing/awsy
         - testing/firefox-ui/harness/firefox_ui_harness/runners/update.py
         - testing/gtest
         - testing/marionette
         - testing/mochitest
-        - testing/mozbase
         - testing/mozharness
         - testing/tools/iceserver
         - testing/tps
         - testing/xpcshell
         - testing/web-platform
         - third_party
         - toolkit
         - tools/git