Skip to content

Instantly share code, notes, and snippets.

@CatarinaPBressan
Created December 6, 2017 20:52
Show Gist options
  • Save CatarinaPBressan/4f6dc8b7826e352884f0561ac79d6898 to your computer and use it in GitHub Desktop.
Save CatarinaPBressan/4f6dc8b7826e352884f0561ac79d6898 to your computer and use it in GitHub Desktop.
import collections
from marshmallow.exceptions import ValidationError
from tracker.base import ma
# https://github.com/deckar01/marshmallow/commit/
# b17786048dea2c380b9bb38f33802340f766e53a?diff=unified
class Dict(ma.Field):
"""A dict field. Supports dicts and dict-like objects. Composed by `Fields`
classes and instences for validation.
Example: ::
numbers = fields.Dict(fields.String(), fields.Float())
:param Field key_field: A field class or instance used to validate keys.
:param Field value_field: A field class or instance used to validate
values.
:param kwargs: The same keyword arguments that :class:`Field` receives.
"""
default_error_messages = {
'invalid': 'Not a valid mapping type.'
}
def __init__(self, key_field, value_field, **kwargs):
super(Dict, self).__init__(**kwargs)
self.key_field = key_field
self.value_field = value_field
def _serialize(self, value, attr, obj):
if value is None:
return None
if not isinstance(value, collections.Mapping):
self.fail('invalid')
return dict([
(idx, self.value_field._serialize(each, attr, obj))
for idx, each in value.items()
])
def _deserialize(self, value, attr, data):
if not isinstance(value, collections.Mapping):
self.fail('invalid')
result = {}
errors = {}
for key, value in value.items():
try:
deserialized_key = self.key_field.deserialize(key)
except ValidationError as e:
result.update({key: e.messages})
errors.update({key: e.messages})
deserialized_key = key
try:
result.update({deserialized_key:
self.value_field.deserialize(value)})
except ValidationError as e:
result.update({deserialized_key: e.messages})
errors.update({deserialized_key: e.messages})
if errors:
raise ValidationError(errors, data=result)
return result
@deckar01
Copy link

deckar01 commented Dec 6, 2017

result.update({deserialized_key: self.value_field.deserialize(value)})

It looks like this would leave the original key (and value) in the result dict if the deserialization operation changes it. My strategy is effectively separating the keys and values into lists, deserializing them in place, then zipping them back into a dictionary. This should avoid leaving unprocessed data in the dict.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment