Bug 1425399 - Added python 3 support to mozprofile. r=wlach
authorVedant Chakravadhanula <vedantc98@gmail.com>
Fri, 22 Dec 2017 12:11:06 +0530
changeset 714628 67104a1227e43cee6ff365eff7a3cf7142af5138
parent 714627 834cde6951eed5b427245699f63219a073d1724d
child 714629 286fe0a699dcf9c204058c362a40401fbbbd942f
child 714630 90f70240f40956ab6eba75ecb8f985bb92a8ac22
push id93978
push userbmo:bpostelnicu@mozilla.com
push dateWed, 27 Dec 2017 11:35:02 +0000
reviewerswlach
bugs1425399
milestone59.0a1
Bug 1425399 - Added python 3 support to mozprofile. r=wlach MozReview-Commit-ID: 9iAFA3JYagG
testing/mozbase/mozprofile/mozprofile/addons.py
testing/mozbase/mozprofile/mozprofile/permissions.py
testing/mozbase/mozprofile/mozprofile/prefs.py
testing/mozbase/mozprofile/mozprofile/profile.py
testing/mozbase/mozprofile/setup.py
testing/mozbase/mozprofile/tests/server_locations.py
testing/mozbase/mozprofile/tests/test_addons.py
testing/mozbase/mozprofile/tests/test_preferences.py
--- a/testing/mozbase/mozprofile/mozprofile/addons.py
+++ b/testing/mozbase/mozprofile/mozprofile/addons.py
@@ -4,22 +4,22 @@
 
 from __future__ import absolute_import
 
 import json
 import os
 import sys
 import shutil
 import tempfile
-import urllib2
 import zipfile
 import hashlib
 from xml.dom import minidom
 
-from six import reraise
+from six import reraise, string_types
+from six.moves.urllib import request
 
 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')
@@ -108,17 +108,17 @@ class AddonManager(object):
     def download(self, url, target_folder=None):
         """
         Downloads an add-on from the specified URL to the target folder
 
         :param url: URL of the add-on (XPI file)
         :param target_folder: Folder to store the XPI file in
 
         """
-        response = urllib2.urlopen(url)
+        response = request.urlopen(url)
         fd, path = tempfile.mkstemp(suffix='.xpi')
         os.write(fd, response.read())
         os.close(fd)
 
         if not self.is_addon(path):
             mozfile.remove(path)
             raise AddonFormatError('Not a valid add-on: %s' % url)
 
@@ -172,24 +172,24 @@ class AddonManager(object):
         Installs all types of addons
 
         :param addons: a list of addon paths to install
         :param manifest: a list of addon manifests to install
         """
 
         # install addon paths
         if addons:
-            if isinstance(addons, basestring):
+            if isinstance(addons, string_types):
                 addons = [addons]
             for addon in set(addons):
                 self.install_from_path(addon)
 
         # install addon manifests
         if manifests:
-            if isinstance(manifests, basestring):
+            if isinstance(manifests, string_types):
                 manifests = [manifests]
             for manifest in manifests:
                 self.install_from_manifest(manifest)
 
     def install_from_manifest(self, filepath):
         """
         Installs addons from a manifest
         :param filepath: path to the manifest of addons to install
@@ -230,17 +230,17 @@ class AddonManager(object):
     def get_amo_install_path(self, query):
         """
         Get the addon xpi install path for the specified AMO query.
 
         :param query: query-documentation_
 
         .. _query-documentation: https://developer.mozilla.org/en/addons.mozilla.org_%28AMO%29_API_Developers%27_Guide/The_generic_AMO_API # noqa
         """
-        response = urllib2.urlopen(query)
+        response = request.urlopen(query)
         dom = minidom.parseString(response.read())
         for node in dom.getElementsByTagName('install')[0].childNodes:
             if node.nodeType == node.TEXT_NODE:
                 return node.data
 
     @classmethod
     def _gen_iid(cls, addon_path):
         hash = hashlib.sha1(_SALT)
@@ -348,17 +348,17 @@ class AddonManager(object):
                     # 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:
                 reraise(AddonFormatError(str(e)), None, sys.exc_info()[2])
 
         # turn unpack into a true/false value
-        if isinstance(details['unpack'], basestring):
+        if isinstance(details['unpack'], string_types):
             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.')
 
         return details
 
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py
+++ b/testing/mozbase/mozprofile/mozprofile/permissions.py
@@ -7,17 +7,19 @@
 add permissions to the profile
 """
 
 from __future__ import absolute_import
 
 import codecs
 import os
 import sqlite3
-import urlparse
+
+from six import string_types
+from six.moves.urllib import parse
 
 __all__ = ['MissingPrimaryLocationError', 'MultiplePrimaryLocationsError',
            'DEFAULT_PORTS', 'DuplicateLocationError', 'BadPortLocationError',
            'LocationsSyntaxError', 'Location', 'ServerLocations',
            'Permissions']
 
 # http://hg.mozilla.org/mozilla-central/file/b871dfb2186f/build/automation.py.in#l28
 DEFAULT_PORTS = {'http': '8888',
@@ -134,17 +136,17 @@ class ServerLocations(object):
                 raise MultiplePrimaryLocationsError()
             self.hasPrimary = True
 
         self._locations.append(location)
         if self.add_callback and not suppress_callback:
             self.add_callback([location])
 
     def add_host(self, host, port='80', scheme='http', options='privileged'):
-        if isinstance(options, basestring):
+        if isinstance(options, string_types):
             options = options.split(',')
         self.add(Location(scheme, host, port, options))
 
     def read(self, filename, check_for_primary=True):
         """
         Reads the file and adds all valid locations to the ``self._locations`` array.
 
         :param filename: in the format of server-locations.txt_
@@ -177,17 +179,17 @@ class ServerLocations(object):
                 options = options.split(',')
             except ValueError:
                 server = line
                 options = []
 
             # parse the server url
             if '://' not in server:
                 server = 'http://' + server
-            scheme, netloc, path, query, fragment = urlparse.urlsplit(server)
+            scheme, netloc, path, query, fragment = parse.urlsplit(server)
             # get the host and port
             try:
                 host, port = netloc.rsplit(':', 1)
             except ValueError:
                 host = netloc
                 port = DEFAULT_PORTS.get(scheme, '80')
 
             try:
--- a/testing/mozbase/mozprofile/mozprofile/prefs.py
+++ b/testing/mozbase/mozprofile/mozprofile/prefs.py
@@ -6,18 +6,19 @@
 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
+
+from six.moves.configparser import SafeConfigParser as ConfigParser
+from six import StringIO, string_types
 
 __all__ = ('PreferencesReadError', 'Preferences')
 
 
 class PreferencesReadError(Exception):
     """read error for prefrences files"""
 
 
@@ -59,17 +60,17 @@ class Preferences(object):
         what type the preference value is, as natively it is a string
 
         - integers will get cast to integers
         - true/false will get cast to True/False
         - anything enclosed in single quotes will be treated as a string
           with the ''s removed from both sides
         """
 
-        if not isinstance(value, basestring):
+        if not isinstance(value, string_types):
             return value  # no op
         quote = "'"
         if value == 'true':
             return True
         if value == 'false':
             return False
         try:
             return int(value)
@@ -141,17 +142,17 @@ class Preferences(object):
         if isinstance(prefs, list):
             if [i for i in prefs if type(i) != list or len(i) != 2]:
                 raise PreferencesReadError("Malformed preferences: %s" % path)
             values = [i[1] for i in prefs]
         elif isinstance(prefs, dict):
             values = prefs.values()
         else:
             raise PreferencesReadError("Malformed preferences: %s" % path)
-        types = (bool, basestring, int)
+        types = (bool, string_types, int)
         if [i for i in values if not [isinstance(i, j) for j in types]]:
             raise PreferencesReadError("Only bool, string, and int values allowed")
         return prefs
 
     @classmethod
     def read_prefs(cls, path, pref_setter='user_pref', interpolation=None):
         """
         Read preferences from (e.g.) prefs.js
@@ -181,53 +182,53 @@ class Preferences(object):
             if token[0] == tokenize.COMMENT:
                 continue
             processed_tokens.append(token[:2])  # [:2] gets around http://bugs.python.org/issue9974
         string = tokenize.untokenize(processed_tokens)
 
         retval = []
 
         def pref(a, b):
-            if interpolation and isinstance(b, basestring):
+            if interpolation and isinstance(b, string_types):
                 b = b.format(**interpolation)
             retval.append((a, b))
         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)
                 raise
 
         # de-magic the marker
         for index, (key, value) in enumerate(retval):
-            if isinstance(value, basestring) and marker in value:
+            if isinstance(value, string_types) and marker in value:
                 retval[index] = (key, value.replace(marker, '//'))
 
         return retval
 
     @classmethod
     def write(cls, _file, prefs, pref_string='user_pref(%s, %s);'):
         """write preferences to a file"""
 
-        if isinstance(_file, basestring):
-            f = file(_file, 'a')
+        if isinstance(_file, string_types):
+            f = open(_file, 'a')
         else:
             f = _file
 
         if isinstance(prefs, dict):
             # order doesn't matter
             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(pref_string % _pref, file=f)
 
         # close the file if opened internally
-        if isinstance(_file, basestring):
+        if isinstance(_file, string_types):
             f.close()
--- a/testing/mozbase/mozprofile/mozprofile/profile.py
+++ b/testing/mozbase/mozprofile/mozprofile/profile.py
@@ -250,17 +250,17 @@ class Profile(object):
 
     def pop_preferences(self, filename):
         """
         pop the last set of preferences added
         returns True if popped
         """
 
         path = os.path.join(self.profile, filename)
-        with file(path) as f:
+        with open(path) as f:
             lines = f.read().splitlines()
 
         def last_index(_list, value):
             """
             returns the last index of an item;
             this should actually be part of python code but it isn't
             """
             for index in reversed(range(len(_list))):
@@ -277,17 +277,17 @@ class Profile(object):
             assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])
 
         # ensure the markers are in the proper order
         assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e,
                                                                 self.delimeters[0], s)
 
         # write the prefs
         cleaned_prefs = '\n'.join(lines[:s] + lines[e + 1:])
-        with file(path, 'w') as f:
+        with open(path, 'w') as f:
             f.write(cleaned_prefs)
         return True
 
     # methods for introspection
 
     def summary(self, return_parts=False):
         """
         returns string summarizing profile information.
--- a/testing/mozbase/mozprofile/setup.py
+++ b/testing/mozbase/mozprofile/setup.py
@@ -1,38 +1,35 @@
 # 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.29'
 
-# we only support python 2 right now
-assert sys.version_info[0] == 2
-
 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 https://firefox-source-docs.mozilla.org/mozbase/index.html",
       classifiers=['Environment :: Console',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)',
                    'Natural Language :: English',
                    'Operating System :: OS Independent',
-                   'Programming Language :: Python',
+                   'Programming Language :: Python :: 2.7',
+                   'Programming Language :: Python :: 3',
                    'Topic :: Software Development :: Libraries :: Python Modules',
                    ],
       keywords='mozilla',
       author='Mozilla Automation and Tools team',
       author_email='tools@lists.mozilla.org',
       url='https://wiki.mozilla.org/Auto-tools/Projects/Mozbase',
       license='MPL 2.0',
       packages=['mozprofile'],
--- a/testing/mozbase/mozprofile/tests/server_locations.py
+++ b/testing/mozbase/mozprofile/tests/server_locations.py
@@ -60,31 +60,31 @@ http://example.org:80           privileg
         f = self.create_temp_file(self.locations)
 
         # read the locations
         locations = ServerLocations(f.name)
 
         # ensure that they're what we expect
         self.assertEqual(len(locations), 6)
         i = iter(locations)
-        self.compare_location(i.next(), 'http', 'mochi.test', '8888',
+        self.compare_location(next(i), 'http', 'mochi.test', '8888',
                               ['primary', 'privileged'])
-        self.compare_location(i.next(), 'http', '127.0.0.1', '80',
+        self.compare_location(next(i), 'http', '127.0.0.1', '80',
                               ['privileged'])
-        self.compare_location(i.next(), 'http', '127.0.0.1', '8888',
+        self.compare_location(next(i), 'http', '127.0.0.1', '8888',
                               ['privileged'])
-        self.compare_location(i.next(), 'https', 'test', '80', ['privileged'])
-        self.compare_location(i.next(), 'http', 'example.org', '80',
+        self.compare_location(next(i), 'https', 'test', '80', ['privileged'])
+        self.compare_location(next(i), 'http', 'example.org', '80',
                               ['privileged'])
-        self.compare_location(i.next(), 'http', 'test1.example.org', '8888',
+        self.compare_location(next(i), 'http', 'test1.example.org', '8888',
                               ['privileged'])
 
         locations.add_host('mozilla.org')
         self.assertEqual(len(locations), 7)
-        self.compare_location(i.next(), 'http', 'mozilla.org', '80',
+        self.compare_location(next(i), 'http', 'mozilla.org', '80',
                               ['privileged'])
 
         # test some errors
         self.assertRaises(MultiplePrimaryLocationsError, locations.add_host,
                           'primary.test', options='primary')
 
         # We no longer throw these DuplicateLocation Error
         try:
--- a/testing/mozbase/mozprofile/tests/test_addons.py
+++ b/testing/mozbase/mozprofile/tests/test_addons.py
@@ -5,28 +5,28 @@
 # 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
 
 from manifestparser import ManifestParser
 import mozfile
 import mozhttpd
 import mozlog.unstructured as mozlog
 import mozprofile
 
 from addon_stubs import generate_addon, generate_manifest
+from six.moves.urllib import error
 
 
 here = os.path.dirname(os.path.abspath(__file__))
 
 
 class TestAddonsManager(unittest.TestCase):
     """ Class to test mozprofile.addons.AddonManager """
 
@@ -99,17 +99,17 @@ class TestAddonsManager(unittest.TestCas
         # Download an invalid add-on to a special folder
         addon = server.get_url() + 'invalid.xpi'
         self.assertRaises(mozprofile.addons.AddonFormatError,
                           self.am.download, addon, self.tmpdir)
         self.assertEqual(os.listdir(self.tmpdir), [])
 
         # Download from an invalid URL
         addon = server.get_url() + 'not_existent.xpi'
-        self.assertRaises(urllib2.HTTPError,
+        self.assertRaises(error.HTTPError,
                           self.am.download, addon, self.tmpdir)
         self.assertEqual(os.listdir(self.tmpdir), [])
 
         # Download from an invalid URL
         addon = 'not_existent.xpi'
         self.assertRaises(ValueError,
                           self.am.download, addon, self.tmpdir)
         self.assertEqual(os.listdir(self.tmpdir), [])
@@ -161,17 +161,17 @@ class TestAddonsManager(unittest.TestCas
 
         # Generate installer stubs and install them
         for ext in ['test-addon-1@mozilla.org', 'test-addon-2@mozilla.org']:
             temp_addon = generate_addon(ext, path=self.tmpdir)
             addons_to_install.append(self.am.addon_details(temp_addon)['id'])
             self.am.install_from_path(temp_addon)
 
         # Generate a list of addons installed in the profile
-        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_installed = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
         self.assertEqual(addons_to_install.sort(), addons_installed.sort())
 
     def test_install_from_path_folder(self):
         # Generate installer stubs for all possible types of addons
         addons = []
         addons.append(generate_addon('test-addon-1@mozilla.org',
                                      path=self.tmpdir))
@@ -326,17 +326,17 @@ class TestAddonsManager(unittest.TestCas
         m.read(temp_manifest)
         addons = m.get()
 
         # Obtain details of addons to install from the manifest
         addons_to_install = [self.am.addon_details(x['path']).get('id') for x in addons]
 
         self.am.install_from_manifest(temp_manifest)
         # Generate a list of addons installed in the profile
-        addons_installed = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_installed = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
         self.assertEqual(addons_installed.sort(), addons_to_install.sort())
 
         # Cleanup the temporary addon and manifest directories
         mozfile.rmtree(os.path.dirname(temp_manifest))
 
     def test_addon_details(self):
         # Generate installer stubs for a valid and invalid add-on manifest
@@ -366,27 +366,27 @@ class TestAddonsManager(unittest.TestCas
                           self.am.addon_details, addon_path)
 
     @unittest.skip("Bug 900154")
     def test_clean_addons(self):
         addon_one = generate_addon('test-addon-1@mozilla.org')
         addon_two = generate_addon('test-addon-2@mozilla.org')
 
         self.am.install_addons(addon_one)
-        installed_addons = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        installed_addons = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                             self.profile.profile, 'extensions', 'staged'))]
 
         # Create a new profile based on an existing profile
         # Install an extra addon in the new profile
         # Cleanup addons
         duplicate_profile = mozprofile.profile.Profile(profile=self.profile.profile,
                                                        addons=addon_two)
         duplicate_profile.addon_manager.clean()
 
-        addons_after_cleanup = [unicode(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
+        addons_after_cleanup = [str(x[:-len('.xpi')]) for x in os.listdir(os.path.join(
                                 duplicate_profile.profile, 'extensions', 'staged'))]
         # New addons installed should be removed by clean_addons()
         self.assertEqual(installed_addons, addons_after_cleanup)
 
     def test_noclean(self):
         """test `restore=True/False` functionality"""
 
         server = mozhttpd.MozHttpd(docroot=os.path.join(here, 'addons'))
--- a/testing/mozbase/mozprofile/tests/test_preferences.py
+++ b/testing/mozbase/mozprofile/tests/test_preferences.py
@@ -138,48 +138,48 @@ general.warnOnAboutConfig = False
     def test_reset_should_remove_added_prefs(self):
         """Check that when we call reset the items we expect are updated"""
         profile = Profile()
         prefs_file = os.path.join(profile.profile, 'user.js')
 
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
         prefs1 = [("mr.t.quotes", "i aint getting on no plane!")]
         profile.set_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines))
         self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines))
 
         profile.reset()
         self.assertNotEqual(prefs1,
                             Preferences.read_prefs(os.path.join(profile.profile, 'user.js')),
                             "I pity the fool who left my pref")
 
     def test_reset_should_keep_user_added_prefs(self):
         """Check that when we call reset the items we expect are updated"""
         profile = Profile()
         prefs_file = os.path.join(profile.profile, 'user.js')
 
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
         prefs1 = [("mr.t.quotes", "i aint getting on no plane!")]
         profile.set_persistent_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(any(line.startswith('#MozRunner Prefs Start') for line in lines))
         self.assertTrue(any(line.startswith('#MozRunner Prefs End') for line in lines))
 
         profile.reset()
         self.assertEqual(prefs1,
                          Preferences.read_prefs(os.path.join(profile.profile, 'user.js')),
                          "I pity the fool who left my pref")
 
@@ -187,63 +187,63 @@ general.warnOnAboutConfig = False
         """ensure our magic markers are working"""
 
         profile = Profile()
         prefs_file = os.path.join(profile.profile, 'user.js')
 
         # we shouldn't have any initial preferences
         initial_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(initial_prefs)
-        initial_prefs = file(prefs_file).read().strip()
+        initial_prefs = open(prefs_file).read().strip()
         self.assertFalse(initial_prefs)
 
         # add some preferences
         prefs1 = [("browser.startup.homepage", "http://planet.mozilla.org/"),
                   ("zoom.minPercent", 30)]
         profile.set_preferences(prefs1)
         self.assertEqual(prefs1, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(bool([line for line in lines
                               if line.startswith('#MozRunner Prefs Start')]))
         self.assertTrue(bool([line for line in lines
                               if line.startswith('#MozRunner Prefs End')]))
 
         # add some more preferences
         prefs2 = [("zoom.maxPercent", 300),
                   ("webgl.verbose", 'false')]
         profile.set_preferences(prefs2)
         self.assertEqual(prefs1 + prefs2, Preferences.read_prefs(prefs_file))
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue(len([line for line in lines
                              if line.startswith('#MozRunner Prefs Start')]) == 2)
         self.assertTrue(len([line for line in lines
                              if line.startswith('#MozRunner Prefs End')]) == 2)
 
         # now clean it up
         profile.clean_preferences()
         final_prefs = Preferences.read_prefs(prefs_file)
         self.assertFalse(final_prefs)
-        lines = file(prefs_file).read().strip().splitlines()
+        lines = open(prefs_file).read().strip().splitlines()
         self.assertTrue('#MozRunner Prefs Start' not in lines)
         self.assertTrue('#MozRunner Prefs End' not in lines)
 
     def test_preexisting_preferences(self):
         """ensure you don't clobber preexisting preferences"""
 
         # make a pretend profile
         tempdir = tempfile.mkdtemp()
 
         try:
             # make a user.js
             contents = """
 user_pref("webgl.enabled_for_all_sites", true);
 user_pref("webgl.force-enabled", true);
 """
             user_js = os.path.join(tempdir, 'user.js')
-            f = file(user_js, 'w')
+            f = open(user_js, 'w')
             f.write(contents)
             f.close()
 
             # make sure you can read it
             prefs = Preferences.read_prefs(user_js)
             original_prefs = [('webgl.enabled_for_all_sites', True), ('webgl.force-enabled', True)]
             self.assertTrue(prefs == original_prefs)