Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Custom boolean values #97

Merged
merged 2 commits into from

3 participants

Joe Dallago Tres Seaver lmctv
Joe Dallago
Collaborator

This is a pull request for issue #78. Going to add a few more fixes to it, in addition to @lmctv.

lmctv added some commits
lmctv lmctv Allow custom setting of true/false choices
both on deserialization and on serialization.

Preserve existing behaviour by setting false_choices to ('false', '0'),
true_choices to an empty tuple, false_val to 'false' and true_val to 'true'.

The new behaviour lets the caller use translated strings both in
deserialization and in serialization, as in:

    bool=Boolean(false_choices=(_('no'),_('false'),_('n'),_('f'), '0'),
                 true_choices=(_('yes'),_('true'),_('y'),_('t'), '1'),
                 false_val=_('false'), true_val=_('true'))
94ca41f
lmctv lmctv Add myself to CONTRIBUTORS. 40caaa2
Joe Dallago
Collaborator

In hindsight, this commit appears to be complete. The only change I made was rebase it on the current master, so it can be pulled immediately. Changes were made to the api docs, and any further changes to the user documentation seem unnecessary. Ready to be pulled.

Joe Dallago
Collaborator

Oddly enough, this doesn't seem to be able to be merged directly, but I can merge it locally without problem.

Tres Seaver tseaver merged commit 40caaa2 into from
Tres Seaver
Owner

Thanks @lmctv and @jayd3e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 19, 2013
  1. lmctv Joe Dallago

    Allow custom setting of true/false choices

    lmctv authored jayd3e committed
    both on deserialization and on serialization.
    
    Preserve existing behaviour by setting false_choices to ('false', '0'),
    true_choices to an empty tuple, false_val to 'false' and true_val to 'true'.
    
    The new behaviour lets the caller use translated strings both in
    deserialization and in serialization, as in:
    
        bool=Boolean(false_choices=(_('no'),_('false'),_('n'),_('f'), '0'),
                     true_choices=(_('yes'),_('true'),_('y'),_('t'), '1'),
                     false_val=_('false'), true_val=_('true'))
  2. lmctv Joe Dallago

    Add myself to CONTRIBUTORS.

    lmctv authored jayd3e committed
This page is out of date. Refresh to see the latest.
1  CONTRIBUTORS.txt
View
@@ -108,3 +108,4 @@ Contributors
- Daniel Nouri, 2012/03/28
- Gary van der Merwe, 2012/04/05
- Domen Kožar, 2012/04/16
+- Lorenzo M. Catucci, 2013/01/29
54 colander/__init__.py
View
@@ -1189,12 +1189,31 @@ def __init__(self):
class Boolean(SchemaType):
""" A type representing a boolean object.
- During deserialization, a value in the set (``false``, ``0``) will
- be considered ``False``. Anything else is considered
- ``True``. Case is ignored.
+ The constructor accepts these keyword arguments:
+
+ - ``false_choices``: The set of strings representing a ``False``
+ value on deserialization.
+
+ - ``true_choices``: The set of strings representing a ``True``
+ value on deserialization.
+
+ - ``false_val``: The value returned on serialization of a False
+ value.
+
+ - ``true_val``: The value returned on serialization of a True
+ value.
+
+ During deserialization, a value contained in :attr:`false_choices`,
+ will be considered ``False``.
- Serialization will produce ``true`` or ``false`` based on the
- value.
+ The behaviour for values not contained in :attr:`false_choices`
+ depends on :attr:`true_choices`: if it's empty, any value is considered
+ ``True``; otherwise, only values contained in :attr:`true_choices`
+ are considered ``True``, and an Invalid exception would be raised
+ for values outside of both :attr:`false_choices` and :attr:`true_choices`.
+
+ Serialization will produce :attr:`true_val` or :attr:`false_val`
+ based on the value.
If the :attr:`colander.null` value is passed to the serialize
method of this class, the :attr:`colander.null` value will be
@@ -1203,12 +1222,22 @@ class Boolean(SchemaType):
The subnodes of the :class:`colander.SchemaNode` that wraps
this type are ignored.
"""
+ def __init__(self, false_choices=('false', '0'), true_choices=(),
+ false_val='false', true_val='true'):
+
+ self.false_choices = false_choices
+ self.true_choices = true_choices
+ self.false_val = false_val
+ self.true_val = true_val
+
+ self.true_reprs = ', '.join([repr(c) for c in self.true_choices])
+ self.false_reprs = ', '.join([repr(c) for c in self.false_choices])
def serialize(self, node, appstruct):
if appstruct is null:
return null
- return appstruct and 'true' or 'false'
+ return appstruct and self.true_val or self.false_val
def deserialize(self, node, cstruct):
if cstruct is null:
@@ -1222,8 +1251,19 @@ def deserialize(self, node, cstruct):
)
result = result.lower()
- if result in ('false', '0'):
+ if result in self.false_choices:
return False
+ elif self.true_choices:
+ if result in self.true_choices:
+ return True
+ else:
+ raise Invalid(node,
+ _('"${val}" is neither in (${false_choices}) '
+ 'nor in (${true_choices})',
+ mapping={'val':cstruct,
+ 'false_choices': self.false_reprs,
+ 'true_choices': self.true_reprs })
+ )
return True
46 colander/tests/test_colander.py
View
@@ -1582,6 +1582,52 @@ def test_serialize(self):
self.assertEqual(typ.serialize(node, None), 'false')
self.assertEqual(typ.serialize(node, False), 'false')
+class TestBooleanCustomFalseReprs(unittest.TestCase):
+ def _makeOne(self):
+ from colander import Boolean
+ return Boolean(false_choices=('n','f'))
+
+ def test_deserialize(self):
+ import colander
+ typ = self._makeOne()
+ node = DummySchemaNode(None)
+ self.assertEqual(typ.deserialize(node, 'f'), False)
+ self.assertEqual(typ.deserialize(node, 'N'), False)
+ self.assertEqual(typ.deserialize(node, 'other'), True)
+
+class TestBooleanCustomFalseAndTrueReprs(unittest.TestCase):
+ def _makeOne(self):
+ from colander import Boolean
+ return Boolean(false_choices=('n','f'), true_choices=('y','t'))
+
+ def test_deserialize(self):
+ import colander
+ typ = self._makeOne()
+ node = DummySchemaNode(None)
+ self.assertEqual(typ.deserialize(node, 'f'), False)
+ self.assertEqual(typ.deserialize(node, 'N'), False)
+ self.assertEqual(typ.deserialize(node, 'T'), True)
+ self.assertEqual(typ.deserialize(node, 'y'), True)
+ self.assertRaises(colander.Invalid, typ.deserialize, node, 'other')
+ try:
+ _val = typ.deserialize(node, 'other')
+ except colander.Invalid, exc:
+ self.assertEqual(exc.msg.mapping['false_choices'], "'n', 'f'")
+ self.assertEqual(exc.msg.mapping['true_choices'], "'y', 't'")
+
+class TestBooleanCustomSerializations(unittest.TestCase):
+ def _makeOne(self):
+ from colander import Boolean
+ return Boolean(false_val='no', true_val='yes')
+
+ def test_serialize(self):
+ typ = self._makeOne()
+ node = DummySchemaNode(None)
+ self.assertEqual(typ.serialize(node, 1), 'yes')
+ self.assertEqual(typ.serialize(node, True), 'yes')
+ self.assertEqual(typ.serialize(node, None), 'no')
+ self.assertEqual(typ.serialize(node, False), 'no')
+
class TestGlobalObject(unittest.TestCase):
def _makeOne(self, package=None):
from colander import GlobalObject
Something went wrong with that request. Please try again.