From 15bd7d30e095c94bcfdeeedd1d9fc85635be5efd Mon Sep 17 00:00:00 2001 From: Hong Minhee Date: Wed, 4 Nov 2015 13:54:22 +0900 Subject: [PATCH] Add normalize option to Decimal type --- CHANGES.rst | 3 +++ colander/__init__.py | 16 ++++++++++------ colander/tests/test_colander.py | 21 +++++++++++++++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 63a0a77..a67898a 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -23,6 +23,9 @@ Features - Add `NoneOf` validator wich succeeds if the value is none of the choices. +- Add ``normalize`` option to ``Decimal``, stripping the rightmost + trailing zeros. + Bug Fixes --------- diff --git a/colander/__init__.py b/colander/__init__.py index 7e1e686..35f0715 100644 --- a/colander/__init__.py +++ b/colander/__init__.py @@ -1305,24 +1305,27 @@ class Decimal(Number): 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, + The Decimal constructor takes three optional arguments, ``quant``, + ``rounding`` and ``normalize``. If supplied, ``quant`` should be a string, (e.g. ``1.00``). 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. + ignored if ``quant`` is not supplied. If ``normalize`` is ``True``, + the serialized and deserialized result will be normalized by stripping + the rightmost trailing zeros. The subnodes of the :class:`colander.SchemaNode` that wraps this type are ignored. """ - def __init__(self, quant=None, rounding=None): + def __init__(self, quant=None, rounding=None, normalize=False): if quant is None: self.quant = None else: self.quant = decimal.Decimal(quant) self.rounding = rounding + self.normalize = normalize def num(self, val): result = decimal.Decimal(str(val)) @@ -1331,6 +1334,8 @@ class Decimal(Number): result = result.quantize(self.quant) else: result = result.quantize(self.quant, self.rounding) + if self.normalize: + result = result.normalize() return result class Money(Decimal): @@ -1346,8 +1351,7 @@ class Money(Decimal): this type are ignored. """ def __init__(self): - self.quant = decimal.Decimal('.01') - self.rounding = decimal.ROUND_UP + super(Money, self).__init__(decimal.Decimal('.01'), decimal.ROUND_UP) class Boolean(SchemaType): """ A type representing a boolean object. diff --git a/colander/tests/test_colander.py b/colander/tests/test_colander.py index aba64e9..a35ecd0 100644 --- a/colander/tests/test_colander.py +++ b/colander/tests/test_colander.py @@ -1691,9 +1691,9 @@ class TestFloat(unittest.TestCase): self.assertEqual(result, '1.0') class TestDecimal(unittest.TestCase): - def _makeOne(self, quant=None, rounding=None): + def _makeOne(self, quant=None, rounding=None, normalize=False): from colander import Decimal - return Decimal(quant, rounding) + return Decimal(quant, rounding, normalize) def test_serialize_null(self): import colander @@ -1725,6 +1725,14 @@ class TestDecimal(unittest.TestCase): result = typ.serialize(node, val) self.assertEqual(result, '0.01') + def test_serialize_normalize(self): + from decimal import Decimal + val = Decimal('1.00') + node = DummySchemaNode(None) + typ = self._makeOne(normalize=True) + result = typ.serialize(node, val) + self.assertEqual(result, '1') + def test_deserialize_fails(self): val = 'P' node = DummySchemaNode(None) @@ -1748,6 +1756,15 @@ class TestDecimal(unittest.TestCase): result = typ.deserialize(node, val) self.assertEqual(result, decimal.Decimal('1.01')) + def test_deserialize_with_normalize(self): + from decimal import Decimal + val = '1.00' + node = DummySchemaNode(None) + typ = self._makeOne(normalize=True) + result = typ.deserialize(node, val) + self.assertEqual(result, Decimal('1')) + self.assertEqual(str(result), '1') + def test_serialize_fails(self): val = 'P' node = DummySchemaNode(None)