Commits

Christopher Peplin committed 2492a97

Patch the majority of the issues with running units in Python 3.

The changes are mostly due to:

* __cmp__ is deprecated in favor of __lt__ for sorting and the explicit __le__,
__gt__, __eq__, etc. operators.
* cmp is no longer a builtin
* Objects are no longer implicitly sortable by their memory address
* Division is now overloaded with __truediv__ (/) and __floordiv__ (//)

There is one remaining issue that causes the tests to fail in Python 3.3, a
change in floating point to string conversion. I will commit that next
separately from these changes, as it is the only fix that requires any semantic
changes in the library.

Comments (0)

Files changed (4)

units/composed_unit.py

     def invert(self):
         """Return (this unit)^-1."""
         return ComposedUnit(self.denom, self.numer, 1 / self.squeeze())
-        
-    def __div__(self, other):
+
+    def __truediv__(self, other):
         if hasattr(other, "invert"):
             return self * other.invert()
         else:
             return ComposedUnit(self.numer, 
                                 self.denom + [other], 
                                 self.squeeze() / other.squeeze())
-                                
+
+    # Backwards-compatibility for <= Python 2.7
+    __div__ = __truediv__
+
     def __pow__(self, exponent):
         return ComposedUnit(self.numer * exponent, 
                             self.denom * exponent, 

units/leaf_unit.py

     def str_includes_multiplier(self):
         return True
 
+    def __lt__(self, other):
+        """In Python <= 2.7, objects without a __cmp__ method could be
+        implicitly compared by their ids. It gave a consistent order within a
+        single program run. The __lt__ method is now required for sorting, and
+        here we just use the identity which should have the same effect.
+        """
+        return id(self) < id(other)
+
     def __repr__(self):
         return ("LeafUnit(" + 
                 ", ".join([repr(x) for x in [self.specifier,
             return other * self
         else:
             return ComposedUnit([self, other], [])
-    
-    def __div__(self, other):
+
+    def __truediv__(self, other):
         if hasattr(other, "invert"):
             return other.invert() * self
         else:
             return ComposedUnit([self], [other])
-    
+
+    # Backwards-compatibility for <= Python 2.7
+    __div__ = __truediv__
+
     def invert(self):
         """Return (this unit)^-1"""
         return ComposedUnit([], [self])

units/named_composed_unit.py

     
     def __mul__(self, other):
         return ComposedUnit([self, other], [])
-    
-    def __div__(self, other):
+
+    def __truediv__(self, other):
         return ComposedUnit([self], [other])
-        
+
+    # Backwards-compatibility for <= Python 2.7
+    __div__ = __truediv__
+
     __str__ = get_name
     
     def str_includes_multiplier(self):

units/quantity.py

     
     def __rmul__(self, other):
         return self * other
-    
-    def __div__(self, other):
+
+    def __truediv__(self, other):
         if hasattr(other, 'num'):
             new_unit = self.unit / other.unit
             if hasattr(new_unit, "squeeze"):
             
         else:
             return Quantity(self.num / other, self.unit)
-    
-    def __rdiv__(self, other):
+
+    __floordiv__ = __truediv__
+    # Backwards-compatibility for <= Python 2.7
+    __div__ = __truediv__
+
+    def __rtruediv__(self, other):
         return Quantity(other / self.num, self.unit.invert())
-            
+
+    # Backwards-compatibility for <= Python 2.7
+    __rdiv__ = __rtruediv__
+
     def __eq__(self, other):
         if not compatible(self.unit, other.unit):
             return False
         
     def __ne__(self, other):
         return not self == other
-        
-    def __cmp__(self, other):
+
+    def __lt__(self, other):
         self._ensure_same_type(other)
         return cmp(self.num * self.unit.squeeze(),
                 other.num * other.unit.squeeze())
-                
+
+    __cmp__ = __lt__
+
+    def __le__(self, other):
+        return self == other or self < other
+
     def __complex__(self):
         return complex(self.num)
         
     def __float__(self):
         return float(self.num)
-        
+
+    def __index__(self):
+        return self.num
+
     def __hex__(self):
-        return hex(self.num)
-        
+        """Backwards-compatibility with Python <= 2.7."""
+        return hex(self.__index__())
+
     def __int__(self):
         return int(self.num)
                 
         return ("Quantity(" + 
                 ", ".join([repr(x) for x in [self.num, self.unit]]) +
                 ")")
+
+try:
+    cmp
+except NameError:
+    def cmp(a, b):
+        return (a > b) - (a < b)