Bug 1547730 - don't use py2 builtin 'unicode' in mozpack and deps r=glandium
authorJustin Wood <Callek@gmail.com>
Tue, 28 May 2019 14:25:15 +0000
changeset 475899 f6509e01bf77786d6c244586ac20e7b1b6c0450d
parent 475898 af2c8864114c760fb8c119c6b50bd6a87baaa8fc
child 475900 47e737a70bea7123ac7afbd69925a7819254e0c7
push id86529
push userjwood@mozilla.com
push dateTue, 28 May 2019 14:47:17 +0000
treeherderautoland@dbadda4e3c1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium
bugs1547730
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1547730 - don't use py2 builtin 'unicode' in mozpack and deps r=glandium Also adjust 'basestring' usage in some places. Differential Revision: https://phabricator.services.mozilla.com/D28102
python/mozbuild/mozbuild/backend/configenvironment.py
python/mozbuild/mozbuild/configure/__init__.py
python/mozbuild/mozbuild/configure/util.py
python/mozbuild/mozbuild/preprocessor.py
python/mozbuild/mozbuild/util.py
python/mozbuild/mozpack/files.py
python/mozbuild/mozpack/hg.py
--- a/python/mozbuild/mozbuild/backend/configenvironment.py
+++ b/python/mozbuild/mozbuild/backend/configenvironment.py
@@ -17,22 +17,16 @@ import mozpack.path as mozpath
 from mozbuild.util import (
     FileAvoidWrite,
     memoized_property,
     ReadOnlyDict,
 )
 from mozbuild.shellutil import quote as shell_quote
 
 
-if sys.version_info.major == 2:
-    text_type = unicode
-else:
-    text_type = str
-
-
 class BuildConfig(object):
     """Represents the output of configure."""
 
     _CODE_CACHE = {}
 
     def __init__(self):
         self.topsrcdir = None
         self.topobjdir = None
@@ -192,27 +186,27 @@ class ConfigEnvironment(object):
         # Populate a Unicode version of substs. This is an optimization to make
         # moz.build reading faster, since each sandbox needs a Unicode version
         # of these variables and doing it over a thousand times is a hotspot
         # during sandbox execution!
         # Bug 844509 tracks moving everything to Unicode.
         self.substs_unicode = {}
 
         def decode(v):
-            if not isinstance(v, text_type):
+            if not isinstance(v, six.text_type):
                 try:
                     return v.decode('utf-8')
                 except UnicodeDecodeError:
                     return v.decode('utf-8', 'replace')
 
         for k, v in self.substs.items():
             if not isinstance(v, six.string_types):
                 if isinstance(v, Iterable):
                     type(v)(decode(i) for i in v)
-            elif not isinstance(v, text_type):
+            elif not isinstance(v, six.text_type):
                 v = decode(v)
 
             self.substs_unicode[k] = v
 
         self.substs_unicode = ReadOnlyDict(self.substs_unicode)
 
     @property
     def is_artifact_build(self):
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -282,17 +282,17 @@ class ConfigureSandbox(dict):
 
     # The default set of builtins. We expose unicode as str to make sandboxed
     # files more python3-ready.
     BUILTINS = ReadOnlyDict({
         b: getattr(__builtin__, b)
         for b in ('None', 'False', 'True', 'int', 'bool', 'any', 'all', 'len',
                   'list', 'tuple', 'set', 'dict', 'isinstance', 'getattr',
                   'hasattr', 'enumerate', 'range', 'zip', 'AssertionError')
-    }, __import__=forbidden_import, str=unicode)
+    }, __import__=forbidden_import, str=six.text_type)
 
     # Expose a limited set of functions from os.path
     OS = ReadOnlyNamespace(path=ReadOnlyNamespace(**{
         k: getattr(mozpath, k, getattr(os.path, k))
         for k in ('abspath', 'basename', 'dirname', 'isabs', 'join',
                   'normcase', 'normpath', 'realpath', 'relpath')
     }))
 
--- a/python/mozbuild/mozbuild/configure/util.py
+++ b/python/mozbuild/mozbuild/configure/util.py
@@ -4,16 +4,17 @@
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import codecs
 import itertools
 import locale
 import logging
 import os
+import six
 import sys
 from collections import deque
 from contextlib import contextmanager
 from distutils.version import LooseVersion
 
 
 def getpreferredencoding():
     # locale._parse_localename makes locale.getpreferredencoding
@@ -49,17 +50,17 @@ class Version(LooseVersion):
         # Take the first three integer components, stopping at the first
         # non-integer and padding the rest with zeroes.
         (self.major, self.minor, self.patch) = list(itertools.chain(
             itertools.takewhile(lambda x: isinstance(x, int), self.version),
             (0, 0, 0)))[:3]
 
     def __cmp__(self, other):
         # LooseVersion checks isinstance(StringType), so work around it.
-        if isinstance(other, unicode):
+        if isinstance(other, six.text_type):
             other = other.encode('ascii')
         return LooseVersion.__cmp__(self, other)
 
 
 class ConfigureOutputHandler(logging.Handler):
     '''A logging handler class that sends info messages to stdout and other
     messages to stderr.
 
--- a/python/mozbuild/mozbuild/preprocessor.py
+++ b/python/mozbuild/mozbuild/preprocessor.py
@@ -22,16 +22,17 @@ value :
   | \w+  # string identifier or value;
 """
 
 from __future__ import absolute_import, print_function
 
 import sys
 import os
 import re
+import six
 from optparse import OptionParser
 import errno
 from mozbuild.makeutil import Makefile
 
 # hack around win32 mangling our line endings
 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65443
 if sys.platform == "win32":
     import msvcrt
@@ -786,17 +787,17 @@ class Preprocessor:
     # File ops
 
     def do_include(self, args, filters=True):
         """
         Preprocess a given file.
         args can either be a file name, or a file-like object.
         Files should be opened, and will be closed after processing.
         """
-        isName = type(args) == str or type(args) == unicode
+        isName = isinstance(args, six.string_types)
         oldCheckLineNumbers = self.checkLineNumbers
         self.checkLineNumbers = False
         if isName:
             try:
                 args = str(args)
                 if filters:
                     args = self.applyFilters(args)
                 if not os.path.isabs(args):
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -28,21 +28,16 @@ from collections import (
     OrderedDict,
 )
 from io import (
     StringIO,
     BytesIO,
 )
 
 
-if sys.version_info[0] == 3:
-    str_type = str
-else:
-    str_type = basestring
-
 if sys.platform == 'win32':
     _kernel32 = ctypes.windll.kernel32
     _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
 
 
 def exec_(object, globals=None, locals=None):
     """Wrapper around the exec statement to avoid bogus errors like:
 
@@ -73,17 +68,17 @@ def hash_file(path, hasher=None):
             if not len(data):
                 break
 
             h.update(data)
 
     return h.hexdigest()
 
 
-class EmptyValue(unicode):
+class EmptyValue(six.text_type):
     """A dummy type that behaves like an empty string and sequence.
 
     This type exists in order to support
     :py:class:`mozbuild.frontend.reader.EmptyConfig`. It should likely not be
     used elsewhere.
     """
 
     def __init__(self):
@@ -170,17 +165,17 @@ def mkdir(path, not_indexed=False):
     try:
         os.makedirs(path)
     except OSError as e:
         if e.errno != errno.EEXIST:
             raise
 
     if not_indexed:
         if sys.platform == 'win32':
-            if isinstance(path, str_type):
+            if isinstance(path, six.string_types):
                 fn = _kernel32.SetFileAttributesW
             else:
                 fn = _kernel32.SetFileAttributesA
 
             fn(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
         elif sys.platform == 'darwin':
             with open(os.path.join(path, '.metadata_never_index'), 'a'):
                 pass
@@ -224,17 +219,17 @@ class FileAvoidWrite(BytesIO):
         BytesIO.__init__(self)
         self.name = filename
         self._capture_diff = capture_diff
         self._write_to_file = not dry_run
         self.diff = None
         self.mode = mode
 
     def write(self, buf):
-        if isinstance(buf, unicode):
+        if isinstance(buf, six.text_type):
             buf = buf.encode('utf-8')
         BytesIO.write(self, buf)
 
     def avoid_writing_to_file(self):
         self._write_to_file = False
 
     def close(self):
         """Stop accepting writes, compare file contents, and rewrite if needed.
@@ -816,17 +811,17 @@ class HierarchicalStringList(object):
         exports = self._get_exportvariable(name)
         exports._check_list(value)
         exports._strings += value
 
     def _check_list(self, value):
         if not isinstance(value, list):
             raise ValueError('Expected a list of strings, not %s' % type(value))
         for v in value:
-            if not isinstance(v, str_type):
+            if not isinstance(v, six.string_types):
                 raise ValueError(
                     'Expected a list of strings, not an element of %s' % type(v))
 
 
 class LockFile(object):
     """LockFile is used by the lock_file method to hold the lock.
 
     This object should not be used directly, but only through
@@ -1187,17 +1182,17 @@ class DefinesAction(argparse.Action):
         defines[name] = value
         setattr(namespace, self.dest, defines)
 
 
 class EnumStringComparisonError(Exception):
     pass
 
 
-class EnumString(unicode):
+class EnumString(six.text_type):
     '''A string type that only can have a limited set of values, similarly to
     an Enum, and can only be compared against that set of values.
 
     The class is meant to be subclassed, where the subclass defines
     POSSIBLE_VALUES. The `subclass` method is a helper to create such
     subclasses.
     '''
     POSSIBLE_VALUES = ()
@@ -1224,17 +1219,17 @@ class EnumString(unicode):
         return EnumStringSubclass
 
 
 def _escape_char(c):
     # str.encode('unicode_espace') doesn't escape quotes, presumably because
     # quoting could be done with either ' or ".
     if c == "'":
         return "\\'"
-    return unicode(c.encode('unicode_escape'))
+    return six.text_type(c.encode('unicode_escape'))
 
 
 # Mapping table between raw characters below \x80 and their escaped
 # counterpart, when they differ
 _INDENTED_REPR_TABLE = {
     c: e
     for c, e in map(lambda x: (x, _escape_char(x)),
                     map(unichr, range(128)))
@@ -1264,17 +1259,17 @@ def indented_repr(o, indent=4):
                 for d in recurse_indented_repr(v, level + 1):
                     yield d
                 yield ',\n'
             yield one_indent * level
             yield '}'
         elif isinstance(o, bytes):
             yield 'b'
             yield repr(o)
-        elif isinstance(o, unicode):
+        elif isinstance(o, six.text_type):
             yield "'"
             # We want a readable string (non escaped unicode), but some
             # special characters need escaping (e.g. \n, \t, etc.)
             for i, s in enumerate(_INDENTED_REPR_RE.split(o)):
                 if i % 2:
                     for c in s:
                         yield _INDENTED_REPR_TABLE[c]
                 else:
@@ -1298,17 +1293,17 @@ def encode(obj, encoding='utf-8'):
     '''Recursively encode unicode strings with the given encoding.'''
     if isinstance(obj, dict):
         return {
             encode(k, encoding): encode(v, encoding)
             for k, v in six.iteritems(obj)
         }
     if isinstance(obj, bytes):
         return obj
-    if isinstance(obj, unicode):
+    if isinstance(obj, six.text_type):
         return obj.encode(encoding)
     if isinstance(obj, Iterable):
         return [encode(i, encoding) for i in obj]
     return obj
 
 
 def patch_main():
     '''This is a hack to work around the fact that Windows multiprocessing needs
@@ -1392,17 +1387,17 @@ def patch_main():
             cmdline = orig_command_line()
             cmdline[2] = fork_string
             return cmdline
         orig_command_line = forking.get_command_line
         forking.get_command_line = my_get_command_line
 
 
 def ensure_bytes(value):
-    if isinstance(value, basestring):
+    if isinstance(value, six.text_type):
         return value.encode('utf8')
     return value
 
 
 def ensure_unicode(value):
     if isinstance(value, type(b'')):
         return value.decode('utf8')
     return value
--- a/python/mozbuild/mozpack/files.py
+++ b/python/mozbuild/mozpack/files.py
@@ -63,17 +63,17 @@ if platform.system() != 'Windows':
 else:
     import ctypes
     _kernel32 = ctypes.windll.kernel32
     _CopyFileA = _kernel32.CopyFileA
     _CopyFileW = _kernel32.CopyFileW
 
     def _copyfile(src, dest):
         # False indicates `dest` should be overwritten if it exists already.
-        if isinstance(src, unicode) and isinstance(dest, unicode):
+        if isinstance(src, six.text_type) and isinstance(dest, six.text_type):
             _CopyFileW(src, dest, False)
         elif isinstance(src, str) and isinstance(dest, str):
             _CopyFileA(src, dest, False)
         else:
             raise TypeError('mismatched path types!')
 
 
 class Dest(object):
--- a/python/mozbuild/mozpack/hg.py
+++ b/python/mozbuild/mozpack/hg.py
@@ -27,16 +27,17 @@
 # do not wish to do so, delete this exception statement from your
 # version.
 
 from __future__ import absolute_import, print_function, unicode_literals
 
 import mercurial.error as error
 import mercurial.hg as hg
 import mercurial.ui as hgui
+import six
 
 from .files import (
     BaseFinder,
     MercurialFile,
 )
 import mozpack.path as mozpath
 
 
@@ -51,17 +52,17 @@ class MercurialNativeFile(MercurialFile)
 
 
 class MercurialNativeRevisionFinder(BaseFinder):
     def __init__(self, repo, rev='.', recognize_repo_paths=False):
         """Create a finder attached to a specific changeset.
 
         Accepts a Mercurial localrepo and changectx instance.
         """
-        if isinstance(repo, (str, unicode)):
+        if isinstance(repo, six.string_types):
             path = repo
             repo = hg.repository(hgui.ui(), repo)
         else:
             path = repo.root
 
         super(MercurialNativeRevisionFinder, self).__init__(base=repo.root)
 
         self._repo = repo
@@ -80,16 +81,16 @@ class MercurialNativeRevisionFinder(Base
             if not path.startswith(self._root):
                 raise ValueError('lookups in recognize_repo_paths mode must be '
                                  'prefixed with repo path: %s' % path)
             path = path[len(self._root) + 1:]
 
         return self._get(path)
 
     def _get(self, path):
-        if isinstance(path, unicode):
+        if isinstance(path, six.text_type):
             path = path.encode('utf-8', 'replace')
 
         try:
             fctx = self._repo.filectx(path, self._rev)
             return MercurialNativeFile(fctx.data())
         except error.LookupError:
             return None