diff --git a/python/mozbuild/mozbuild/configure/util.py b/python/mozbuild/mozbuild/configure/util.py index 8628c5588977..8120b071ff19 100644 --- a/python/mozbuild/mozbuild/configure/util.py +++ b/python/mozbuild/mozbuild/configure/util.py @@ -54,11 +54,30 @@ class Version(LooseVersion): itertools.takewhile(lambda x: isinstance(x, int), self.version), (0, 0, 0)))[:3] - def __cmp__(self, other): + def _cmp(self, other): # LooseVersion checks isinstance(StringType), so work around it. - if isinstance(other, six.text_type): + if six.PY2 and isinstance(other, six.text_type): other = other.encode('ascii') - return LooseVersion.__cmp__(self, other) + if six.PY2: + return LooseVersion.__cmp__(self, other) + return LooseVersion._cmp(self, other) + + # These method definitions can be deleted when we remove support for Python + # 2. + def __eq__(self, other): + return self._cmp(other) == 0 + + def __lt__(self, other): + return self._cmp(other) < 0 + + def __le__(self, other): + return self._cmp(other) <= 0 + + def __gt__(self, other): + return self._cmp(other) > 0 + + def __ge__(self, other): + return self._cmp(other) >= 0 class ConfigureOutputHandler(logging.Handler): diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index 64acc355944b..3394115eee53 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -704,29 +704,39 @@ class Path(ContextDerivedValue, six.text_type): return Path(self.context, mozpath.join(self, *p)) def __cmp__(self, other): - if isinstance(other, Path) and self.srcdir != other.srcdir: - return cmp(self.full_path, other.full_path) - return cmp(six.text_type(self), other) + # We expect this function to never be called to avoid issues in the + # switch from Python 2 to 3. + raise AssertionError() - # __cmp__ is not enough because unicode has __eq__, __ne__, etc. defined - # and __cmp__ is only used for those when they don't exist. def __eq__(self, other): - return self.__cmp__(other) == 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path == other.full_path + return six.text_type(self) == other def __ne__(self, other): - return self.__cmp__(other) != 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path != other.full_path + return six.text_type(self) != other def __lt__(self, other): - return self.__cmp__(other) < 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path < other.full_path + return six.text_type(self) < other def __gt__(self, other): - return self.__cmp__(other) > 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path > other.full_path + return six.text_type(self) > other def __le__(self, other): - return self.__cmp__(other) <= 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path <= other.full_path + return six.text_type(self) <= other def __ge__(self, other): - return self.__cmp__(other) >= 0 + if isinstance(other, Path) and self.srcdir != other.srcdir: + return self.full_path >= other.full_path + return six.text_type(self) >= other def __repr__(self): return '<%s (%s)%s>' % (self.__class__.__name__, self.srcdir, self) diff --git a/python/mozbuild/mozbuild/test/frontend/test_namespaces.py b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py index 630c94b43ad5..b434dbf6ba11 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_namespaces.py +++ b/python/mozbuild/mozbuild/test/frontend/test_namespaces.py @@ -4,6 +4,7 @@ from __future__ import absolute_import, print_function, unicode_literals +import six import unittest from mozunit import main @@ -29,7 +30,7 @@ class Fuga(object): class Piyo(ContextDerivedValue): def __init__(self, context, value): - if not isinstance(value, unicode): + if not isinstance(value, six.text_type): raise ValueError self.context = context self.value = value @@ -40,17 +41,29 @@ class Piyo(ContextDerivedValue): def __str__(self): return self.value - def __cmp__(self, other): - return cmp(self.value, str(other)) + def __eq__(self, other): + return self.value == six.text_type(other) + + def __lt__(self, other): + return self.value < six.text_type(other) + + def __le__(self, other): + return self.value <= six.text_type(other) + + def __gt__(self, other): + return self.value > six.text_type(other) + + def __ge__(self, other): + return self.value >= six.text_type(other) def __hash__(self): return hash(self.value) VARIABLES = { - 'HOGE': (unicode, unicode, None), - 'FUGA': (Fuga, unicode, None), - 'PIYO': (Piyo, unicode, None), + 'HOGE': (six.text_type, six.text_type, None), + 'FUGA': (Fuga, six.text_type, None), + 'PIYO': (Piyo, six.text_type, None), 'HOGERA': (ContextDerivedTypedList(Piyo, StrictOrderingOnAppendList), list, None), 'HOGEHOGE': (ContextDerivedTypedListWithItems( @@ -105,7 +118,7 @@ class TestContext(unittest.TestCase): self.assertEqual(e[1], 'set_type') self.assertEqual(e[2], 'HOGE') self.assertEqual(e[3], True) - self.assertEqual(e[4], unicode) + self.assertEqual(e[4], six.text_type) def test_key_checking(self): # Checking for existence of a key should not populate the key if it @@ -128,7 +141,7 @@ class TestContext(unittest.TestCase): self.assertEqual(e[1], 'set_type') self.assertEqual(e[2], 'FUGA') self.assertEqual(e[3], False) - self.assertEqual(e[4], unicode) + self.assertEqual(e[4], six.text_type) ns['FUGA'] = 'fuga' self.assertIsInstance(ns['FUGA'], Fuga) @@ -151,7 +164,7 @@ class TestContext(unittest.TestCase): self.assertEqual(e[1], 'set_type') self.assertEqual(e[2], 'PIYO') self.assertEqual(e[3], False) - self.assertEqual(e[4], unicode) + self.assertEqual(e[4], six.text_type) ns['PIYO'] = 'piyo' self.assertIsInstance(ns['PIYO'], Piyo) diff --git a/python/mozrelease/mozrelease/versions.py b/python/mozrelease/mozrelease/versions.py index 8d40c05717fb..1bcf0f3ddb68 100644 --- a/python/mozrelease/mozrelease/versions.py +++ b/python/mozrelease/mozrelease/versions.py @@ -6,10 +6,25 @@ from __future__ import absolute_import from distutils.version import StrictVersion, LooseVersion import re +from six import PY2 + + +def _cmp(cls, first, other): + # Because the __cmp__ metamethod was removed in the switch to Python 3, the + # interface of the distutils.version.*Version classes changed in a + # backwards-incompatible way. Call this instead of first.__cmp__(other) or + # first._cmp(other) to handle both possibilities. + if PY2: + return cls.__cmp__(first, other) + return cls._cmp(first, other) class MozillaVersionCompareMixin(): def __cmp__(self, other): + # We expect this function to never be called. + raise AssertionError() + + def _cmp(self, other): has_esr = set() if isinstance(other, LooseModernMozillaVersion) and str(other).endswith('esr'): # If other version ends with esr, coerce through MozillaVersion ending up with @@ -25,15 +40,15 @@ class MozillaVersionCompareMixin(): isinstance(self, LooseModernMozillaVersion): # If we're still LooseVersion for self or other, run LooseVersion compare # Being sure to pass through Loose Version type first - val = LooseVersion.__cmp__( - LooseModernMozillaVersion(str(self)), - LooseModernMozillaVersion(str(other))) + val = _cmp(LooseVersion, + LooseModernMozillaVersion(str(self)), + LooseModernMozillaVersion(str(other))) else: # No versions are loose, therefore we can use StrictVersion - val = StrictVersion.__cmp__(self, other) + val = _cmp(StrictVersion, self, other) if has_esr.isdisjoint(set(['other', 'self'])) or \ has_esr.issuperset(set(['other', 'self'])): - # If both had esr string or neither, then cmp() was accurate + # If both had esr string or neither, then _cmp() was accurate return val elif val != 0: # cmp is accurate here even if esr is present in only 1 compare, since @@ -43,6 +58,22 @@ class MozillaVersionCompareMixin(): return -1 # esr is not greater than non esr return 1 # non esr is greater than esr + # These method definitions can be deleted when we drop support for Python 2. + def __eq__(self, other): + return self._cmp(other) == 0 + + def __lt__(self, other): + return self._cmp(other) < 0 + + def __le__(self, other): + return self._cmp(other) <= 0 + + def __gt__(self, other): + return self._cmp(other) > 0 + + def __ge__(self, other): + return self._cmp(other) >= 0 + class ModernMozillaVersion(MozillaVersionCompareMixin, StrictVersion): """A version class that is slightly less restrictive than StrictVersion. diff --git a/python/mozrelease/test/python.ini b/python/mozrelease/test/python.ini index 8d3588d7b23b..7cbba389afd6 100644 --- a/python/mozrelease/test/python.ini +++ b/python/mozrelease/test/python.ini @@ -2,7 +2,6 @@ subsuite=mozrelease [test_versions.py] -skip-if = python == 3 [test_update_verify.py] skip-if = python == 3 [test_balrog.py]