Fixed #12390 -- `Distance` and `Area` objects now support multiplication when they are the right-hand side.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@11898 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Justin Bronn 2009-12-17 18:21:30 +00:00
parent 5bd63663a9
commit fed3081caf
2 changed files with 32 additions and 23 deletions

View File

@ -27,7 +27,7 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# #
""" """
Distance and Area objects to allow for sensible and convienient calculation Distance and Area objects to allow for sensible and convienient calculation
and conversions. and conversions.
Authors: Robert Coup, Justin Bronn Authors: Robert Coup, Justin Bronn
@ -70,7 +70,7 @@ class MeasureBase(object):
@classmethod @classmethod
def unit_attname(cls, unit_str): def unit_attname(cls, unit_str):
""" """
Retrieves the unit attribute name for the given unit string. Retrieves the unit attribute name for the given unit string.
For example, if the given unit string is 'metre', 'm' would be returned. For example, if the given unit string is 'metre', 'm' would be returned.
An exception is raised if an attribute cannot be found. An exception is raised if an attribute cannot be found.
""" """
@ -165,51 +165,51 @@ class Distance(MeasureBase):
self.m, self._default_unit = self.default_units(kwargs) self.m, self._default_unit = self.default_units(kwargs)
if default_unit and isinstance(default_unit, str): if default_unit and isinstance(default_unit, str):
self._default_unit = default_unit self._default_unit = default_unit
def __getattr__(self, name): def __getattr__(self, name):
if name in self.UNITS: if name in self.UNITS:
return self.m / self.UNITS[name] return self.m / self.UNITS[name]
else: else:
raise AttributeError('Unknown unit type: %s' % name) raise AttributeError('Unknown unit type: %s' % name)
def __repr__(self): def __repr__(self):
return 'Distance(%s=%s)' % (self._default_unit, getattr(self, self._default_unit)) return 'Distance(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
def __str__(self): def __str__(self):
return '%s %s' % (getattr(self, self._default_unit), self._default_unit) return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
def __cmp__(self, other): def __cmp__(self, other):
if isinstance(other, Distance): if isinstance(other, Distance):
return cmp(self.m, other.m) return cmp(self.m, other.m)
else: else:
return NotImplemented return NotImplemented
def __add__(self, other): def __add__(self, other):
if isinstance(other, Distance): if isinstance(other, Distance):
return Distance(default_unit=self._default_unit, m=(self.m + other.m)) return Distance(default_unit=self._default_unit, m=(self.m + other.m))
else: else:
raise TypeError('Distance must be added with Distance') raise TypeError('Distance must be added with Distance')
def __iadd__(self, other): def __iadd__(self, other):
if isinstance(other, Distance): if isinstance(other, Distance):
self.m += other.m self.m += other.m
return self return self
else: else:
raise TypeError('Distance must be added with Distance') raise TypeError('Distance must be added with Distance')
def __sub__(self, other): def __sub__(self, other):
if isinstance(other, Distance): if isinstance(other, Distance):
return Distance(default_unit=self._default_unit, m=(self.m - other.m)) return Distance(default_unit=self._default_unit, m=(self.m - other.m))
else: else:
raise TypeError('Distance must be subtracted from Distance') raise TypeError('Distance must be subtracted from Distance')
def __isub__(self, other): def __isub__(self, other):
if isinstance(other, Distance): if isinstance(other, Distance):
self.m -= other.m self.m -= other.m
return self return self
else: else:
raise TypeError('Distance must be subtracted from Distance') raise TypeError('Distance must be subtracted from Distance')
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
return Distance(default_unit=self._default_unit, m=(self.m * float(other))) return Distance(default_unit=self._default_unit, m=(self.m * float(other)))
@ -217,14 +217,17 @@ class Distance(MeasureBase):
return Area(default_unit='sq_' + self._default_unit, sq_m=(self.m * other.m)) return Area(default_unit='sq_' + self._default_unit, sq_m=(self.m * other.m))
else: else:
raise TypeError('Distance must be multiplied with number or Distance') raise TypeError('Distance must be multiplied with number or Distance')
def __imul__(self, other): def __imul__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
self.m *= float(other) self.m *= float(other)
return self return self
else: else:
raise TypeError('Distance must be multiplied with number') raise TypeError('Distance must be multiplied with number')
def __rmul__(self, other):
return self * other
def __div__(self, other): def __div__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
return Distance(default_unit=self._default_unit, m=(self.m / float(other))) return Distance(default_unit=self._default_unit, m=(self.m / float(other)))
@ -251,13 +254,13 @@ class Area(MeasureBase):
self.sq_m, self._default_unit = self.default_units(kwargs) self.sq_m, self._default_unit = self.default_units(kwargs)
if default_unit and isinstance(default_unit, str): if default_unit and isinstance(default_unit, str):
self._default_unit = default_unit self._default_unit = default_unit
def __getattr__(self, name): def __getattr__(self, name):
if name in self.UNITS: if name in self.UNITS:
return self.sq_m / self.UNITS[name] return self.sq_m / self.UNITS[name]
else: else:
raise AttributeError('Unknown unit type: ' + name) raise AttributeError('Unknown unit type: ' + name)
def __repr__(self): def __repr__(self):
return 'Area(%s=%s)' % (self._default_unit, getattr(self, self._default_unit)) return 'Area(%s=%s)' % (self._default_unit, getattr(self, self._default_unit))
@ -269,46 +272,49 @@ class Area(MeasureBase):
return cmp(self.sq_m, other.sq_m) return cmp(self.sq_m, other.sq_m)
else: else:
return NotImplemented return NotImplemented
def __add__(self, other): def __add__(self, other):
if isinstance(other, Area): if isinstance(other, Area):
return Area(default_unit=self._default_unit, sq_m=(self.sq_m + other.sq_m)) return Area(default_unit=self._default_unit, sq_m=(self.sq_m + other.sq_m))
else: else:
raise TypeError('Area must be added with Area') raise TypeError('Area must be added with Area')
def __iadd__(self, other): def __iadd__(self, other):
if isinstance(other, Area): if isinstance(other, Area):
self.sq_m += other.sq_m self.sq_m += other.sq_m
return self return self
else: else:
raise TypeError('Area must be added with Area') raise TypeError('Area must be added with Area')
def __sub__(self, other): def __sub__(self, other):
if isinstance(other, Area): if isinstance(other, Area):
return Area(default_unit=self._default_unit, sq_m=(self.sq_m - other.sq_m)) return Area(default_unit=self._default_unit, sq_m=(self.sq_m - other.sq_m))
else: else:
raise TypeError('Area must be subtracted from Area') raise TypeError('Area must be subtracted from Area')
def __isub__(self, other): def __isub__(self, other):
if isinstance(other, Area): if isinstance(other, Area):
self.sq_m -= other.sq_m self.sq_m -= other.sq_m
return self return self
else: else:
raise TypeError('Area must be subtracted from Area') raise TypeError('Area must be subtracted from Area')
def __mul__(self, other): def __mul__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
return Area(default_unit=self._default_unit, sq_m=(self.sq_m * float(other))) return Area(default_unit=self._default_unit, sq_m=(self.sq_m * float(other)))
else: else:
raise TypeError('Area must be multiplied with number') raise TypeError('Area must be multiplied with number')
def __imul__(self, other): def __imul__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
self.sq_m *= float(other) self.sq_m *= float(other)
return self return self
else: else:
raise TypeError('Area must be multiplied with number') raise TypeError('Area must be multiplied with number')
def __rmul__(self, other):
return self * other
def __div__(self, other): def __div__(self, other):
if isinstance(other, (int, float, long, Decimal)): if isinstance(other, (int, float, long, Decimal)):
return Area(default_unit=self._default_unit, sq_m=(self.sq_m / float(other))) return Area(default_unit=self._default_unit, sq_m=(self.sq_m / float(other)))
@ -324,7 +330,7 @@ class Area(MeasureBase):
def __nonzero__(self): def __nonzero__(self):
return bool(self.sq_m) return bool(self.sq_m)
# Shortcuts # Shortcuts
D = Distance D = Distance
A = Area A = Area

View File

@ -95,6 +95,8 @@ class DistanceTest(unittest.TestCase):
d3 = d1 * 2 d3 = d1 * 2
self.assertEqual(d3.m, 200) self.assertEqual(d3.m, 200)
d3 = 2 * d1
self.assertEqual(d3.m, 200)
d3 *= 5 d3 *= 5
self.assertEqual(d3.m, 1000) self.assertEqual(d3.m, 1000)
@ -248,6 +250,8 @@ class AreaTest(unittest.TestCase):
a3 = a1 * 2 a3 = a1 * 2
self.assertEqual(a3.sq_m, 200) self.assertEqual(a3.sq_m, 200)
a3 = 2 * a1
self.assertEqual(a3.sq_m, 200)
a3 *= 5 a3 *= 5
self.assertEqual(a3.sq_m, 1000) self.assertEqual(a3.sq_m, 1000)
@ -319,7 +323,6 @@ class AreaTest(unittest.TestCase):
self.assertEqual(repr(a1), 'Area(sq_m=100.0)') self.assertEqual(repr(a1), 'Area(sq_m=100.0)')
self.assertEqual(repr(a2), 'Area(sq_km=3.5)') self.assertEqual(repr(a2), 'Area(sq_km=3.5)')
def suite(): def suite():
s = unittest.TestSuite() s = unittest.TestSuite()
s.addTest(unittest.makeSuite(DistanceTest)) s.addTest(unittest.makeSuite(DistanceTest))