Open daveoncode opened 8 years ago
Please create a PR with tests and sign CONTRIBUTORS.txt if you haven't, and we can pull it into colander!
a default for a boolean must always be False by definition
Not to be too pedantic but I don't think that's actually in the definition of a boolean. I can't find anything about what the default should be on wikipedia. Most values actually default to True
exception 0
, None
and a few empty collections in python.
ANYWAY I'm not against changing this, but someone who cares (you) will need to submit a PR with tests as Bret said. :-)
Looking at the source for Boolean
it looks like you can define how you want to serialize/deserialize values. It says:
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`.
So, because the default for false values is 'false' or 0, None
ends up being considered True.
Like most of colander, it's probably a good idea to translate None
values from your database into colander.null
and then you'll get true, false, and null values.
I will submit a PR soon...
in the meanwhile, just google "default boolen value" or try this in a python shell:
assert bool() is False
then...
assert bool() is True
boom! :D
@daveoncode why not add str(None)
as a value to false_choices
?
For example:
class Boolean(colander.Boolean):
"""Overrides the default false_choices to include 'None' unless false_choices is provided."""
def __init__(self, **kwargs):
kwargs["false_choices"] = kwargs.get("false_choices", ('false', '0', str(None)))
super().__init__(
**kwargs,
)
In the code sample you supplied in
https://github.com/Pylons/colander/issues/250#issue-127900218 you return colander.null
which may do what you expect it to do only if you set missing=False
on your SchemaNode
, so it will still not return False
by default.
this is very surprising behavior that just bit me in the ass in production no less.
If I deserialize a dictionary containing
None
as value for a boolean node, Colander falls back toTrue
, which is absolutely wrong... a default for a boolean must always beFalse
by definition. I currently subclassedBoolean
in this way to make it work as expected:But I hope you will consider to replace
True
withFalse
in the last line of originalBoolean
deserialize()
method. Thanks!