- Create a `colander.Money
` type that is a Decimal type with
two-decimal-point precision rounded-up. - Allow ``quant`` and ``rounding`` args to ``colander.Decimal`` constructor.
This commit is contained in:
@@ -7,6 +7,11 @@ Next release
|
||||
- Allow the use of 'missing=None' for Number. See
|
||||
https://github.com/Pylons/colander/pull/59 .
|
||||
|
||||
- Create a ``colander.Money`` type that is a Decimal type with
|
||||
two-decimal-point precision rounded-up.
|
||||
|
||||
- Allow ``quant`` and ``rounding`` args to ``colander.Decimal`` constructor.
|
||||
|
||||
0.9.8 (2012-04-27)
|
||||
------------------
|
||||
|
||||
|
@@ -1000,8 +1000,42 @@ class Float(Number):
|
||||
num = float
|
||||
|
||||
class Decimal(Number):
|
||||
""" A type representing a decimal floating point. Deserialization
|
||||
returns an instance of the Python ``decimal.Decimal`` type.
|
||||
"""
|
||||
A type representing a decimal floating point. Deserialization returns an
|
||||
instance of the Python ``decimal.Decimal`` type.
|
||||
|
||||
If the :attr:`colander.null` value is passed to the serialize
|
||||
method of this class, the :attr:`colander.null` value will be
|
||||
returned.
|
||||
|
||||
The Decimal constructor takes two optional arguments, ``quant`` and
|
||||
``rounding``. If supplied, ``quant`` should be a string. If supplied,
|
||||
``rounding`` should be one of the Python ``decimal`` module rounding
|
||||
options (e.g. ``decimal.ROUND_UP``, ``decimal.ROUND_DOWN``, etc). The
|
||||
serialized and deserialized result will be quantized and rounded via
|
||||
``result.quantize(decimal.Decimal(quant), rounding)``. ``rounding`` is
|
||||
ignored if ``quant`` is not supplied.
|
||||
|
||||
The subnodes of the :class:`colander.SchemaNode` that wraps
|
||||
this type are ignored.
|
||||
"""
|
||||
def __init__(self, quant=None, rounding=None):
|
||||
if quant is None:
|
||||
self.quant = None
|
||||
else:
|
||||
self.quant = decimal.Decimal(quant)
|
||||
self.rounding = rounding
|
||||
|
||||
def num(self, val):
|
||||
result = decimal.Decimal(str(val))
|
||||
if self.quant is not None:
|
||||
result = result.quantize(self.quant, self.rounding)
|
||||
return result
|
||||
|
||||
class Money(Decimal):
|
||||
""" A type representing a money value with two digit precision.
|
||||
Deserialization returns an instance of the Python ``decimal.Decimal``
|
||||
type (quantized to two decimal places, rounded up).
|
||||
|
||||
If the :attr:`colander.null` value is passed to the serialize
|
||||
method of this class, the :attr:`colander.null` value will be
|
||||
@@ -1010,8 +1044,9 @@ class Decimal(Number):
|
||||
The subnodes of the :class:`colander.SchemaNode` that wraps
|
||||
this type are ignored.
|
||||
"""
|
||||
def num(self, val):
|
||||
return decimal.Decimal(str(val))
|
||||
def __init__(self):
|
||||
self.quant = decimal.Decimal('.01')
|
||||
self.rounding = decimal.ROUND_UP
|
||||
|
||||
class Boolean(SchemaType):
|
||||
""" A type representing a boolean object.
|
||||
|
@@ -1249,9 +1249,9 @@ class TestFloat(unittest.TestCase):
|
||||
self.assertEqual(result, '1.0')
|
||||
|
||||
class TestDecimal(unittest.TestCase):
|
||||
def _makeOne(self):
|
||||
def _makeOne(self, quant=None, rounding=None):
|
||||
from colander import Decimal
|
||||
return Decimal()
|
||||
return Decimal(quant, rounding)
|
||||
|
||||
def test_serialize_null(self):
|
||||
import colander
|
||||
@@ -1266,8 +1266,22 @@ class TestDecimal(unittest.TestCase):
|
||||
val = ''
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne()
|
||||
result = typ.deserialize(node, val)
|
||||
self.assertEqual(result, colander.null)
|
||||
self.assertRaises(colander.Invalid, typ.serialize, node, val)
|
||||
|
||||
def test_serialize_quantize_no_rounding(self):
|
||||
val = '.000001'
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne('.01')
|
||||
result = typ.serialize(node, val)
|
||||
self.assertEqual(result, '0.00')
|
||||
|
||||
def test_serialize_quantize_with_rounding_up(self):
|
||||
import decimal
|
||||
val = '.000001'
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne('.01', decimal.ROUND_UP)
|
||||
result = typ.serialize(node, val)
|
||||
self.assertEqual(result, '0.01')
|
||||
|
||||
def test_deserialize_fails(self):
|
||||
val = 'P'
|
||||
@@ -1284,6 +1298,14 @@ class TestDecimal(unittest.TestCase):
|
||||
result = typ.deserialize(node, val)
|
||||
self.assertEqual(result, decimal.Decimal('1.0'))
|
||||
|
||||
def test_deserialize_with_quantize(self):
|
||||
import decimal
|
||||
val = '1.00000001'
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne('.01', decimal.ROUND_UP)
|
||||
result = typ.deserialize(node, val)
|
||||
self.assertEqual(result, decimal.Decimal('1.01'))
|
||||
|
||||
def test_serialize_fails(self):
|
||||
val = 'P'
|
||||
node = DummySchemaNode(None)
|
||||
@@ -1298,6 +1320,26 @@ class TestDecimal(unittest.TestCase):
|
||||
result = typ.serialize(node, val)
|
||||
self.assertEqual(result, '1.0')
|
||||
|
||||
class TestMoney(unittest.TestCase):
|
||||
def _makeOne(self):
|
||||
from colander import Money
|
||||
return Money()
|
||||
|
||||
def test_serialize_rounds_up(self):
|
||||
val = '1.000001'
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne()
|
||||
result = typ.serialize(node, val)
|
||||
self.assertEqual(result, '1.01')
|
||||
|
||||
def test_deserialize_rounds_up(self):
|
||||
import decimal
|
||||
val = '1.00000001'
|
||||
node = DummySchemaNode(None)
|
||||
typ = self._makeOne()
|
||||
result = typ.deserialize(node, val)
|
||||
self.assertEqual(result, decimal.Decimal('1.01'))
|
||||
|
||||
class TestBoolean(unittest.TestCase):
|
||||
def _makeOne(self):
|
||||
from colander import Boolean
|
||||
|
Reference in New Issue
Block a user