Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default normalization rule #172

Merged
merged 6 commits into from
Nov 25, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cerberus/cerberus.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ def __normalize_mapping(self, mapping, schema):
if self.purge_unknown:
self._normalize_purge_unknown(mapping, schema)
self._normalize_coerce(mapping, schema)
self._normalize_default(mapping, schema)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

though i have only one silly argument for setting defaults before coercing, here it is: it seems more intuitive to normalize in that order: purge unwanted items, fill up missing items, work on items.

but maybe it's be useful to coerce a value to None in order to replace it with a default. coercing defaults on the other hand shouldn't make sense.

so propably it's better to keep it like it is. but i'd be interested in other thoughts.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but maybe it's be useful to coerce a value to None in order to replace it with a default. coercing defaults on the other hand shouldn't make sense.

Agreed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but maybe it's be useful to coerce a value to None in order to replace it with a default.

But as told by @nicolaiarocci and I also think the same, using default to replace None seems odd, specially if None is a valid value (nullable fields for example). But I know that maybe becomes handy, that's why I proposed to only override Nones with default only for non nullable fields, but the @nicolaiarocci argument in the comment below seems valid too.

coercing defaults on the other hand shouldn't make sense.

It shouldn't but I don't know if it hurts, maybe it's handy and safer.

self.__normalize_containers(mapping, schema)
return mapping

Expand Down Expand Up @@ -564,6 +565,11 @@ def _normalize_rename_handler(self, mapping, schema, field):
mapping[new_name] = mapping[field]
del mapping[field]

def _normalize_default(self, mapping, schema):
for field in tuple(schema):
if 'default' in schema[field] and field not in mapping:
mapping[field] = schema[field]['default']

# # Validating

def validate(self, document, schema=None, update=False, normalize=True):
Expand Down
39 changes: 39 additions & 0 deletions cerberus/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,45 @@ def test_coercion_of_sequence_items(self):
for x in result['a_list']:
self.assertIsInstance(x, float)

def test_default_missing(self):
schema = {'foo': {'type': 'string'},
'bar': {'type': 'string',
'default': 'bar_value'}}

self.assertSuccess({'foo': 'foo_value'}, schema)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may implement a test-method to test the results of Validator.normalized. there should be some tests that can use it. and more will grow.

result = self.validator.document
self.assertDictEqual(result, {'foo': 'foo_value', 'bar': 'bar_value'})

def test_default_existent(self):
schema = {'foo': {'type': 'string'},
'bar': {'type': 'string',
'default': 'bar_value'}}

self.assertSuccess({'foo': 'foo_value', 'bar': 'non_default'}, schema)
result = self.validator.document
self.assertDictEqual(result, {'foo': 'foo_value', 'bar': 'non_default'})

def test_default_none(self):
schema = {'foo': {'type': 'string'},
'bar': {'type': 'string',
'nullable': True,
'default': 'bar_value'}}

self.assertSuccess({'foo': 'foo_value', 'bar': None}, schema)
result = self.validator.document
self.assertDictEqual(result, {'foo': 'foo_value', 'bar': None})

def test_default_missing_in_subschema(self):
schema = {'thing': {'type': 'dict',
'schema': {'foo': {'type': 'string'},
'bar': {'type': 'string',
'default': 'bar_value'}}}}

self.assertSuccess({'thing': {'foo': 'foo_value'}}, schema)
result = self.validator.document
self.assertDictEqual(result, {'thing': {'foo': 'foo_value',
'bar': 'bar_value'}})


class DefinitionSchema(TestBase):
def test_validated_schema_cache(self):
Expand Down