Skip to content

Instantly share code, notes, and snippets.

@sloria
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sloria/edffc11fac7ee680e544 to your computer and use it in GitHub Desktop.
Save sloria/edffc11fac7ee680e544 to your computer and use it in GitHub Desktop.
proof of concept for integrating 3rd-party validators with marshmallow
"""Proof of concept for converting 3rd-party validators to marshmallow validators,
demonstating multiple possible implementations.
"""
from marshmallow import fields
from marshmallow.exceptions import UnmarshallingError, ValidationError
import pytest
class Converter(object):
__name__ = 'Converter'
def __init__(self, *validators):
self.validators = validators
def make_validator(self, validator):
raise NotImplementedError()
def __call__(self, val):
errors = []
for vendor_validator in self.validators:
validator = self.make_validator(vendor_validator)
try:
validator(val)
except ValidationError as err:
errors.append(str(err))
if errors:
raise ValidationError(errors)
##### wtforms #####
from wtforms.validators import ValidationError as WTFValidationError
from wtforms.validators import AnyOf, NoneOf, Length
# from: https://github.com/wtforms/wtforms/blob/master/tests/common.py
class DummyTranslations(object):
def gettext(self, string):
return string
def ngettext(self, singular, plural, n):
if n == 1:
return singular
return plural
class DummyField(object):
_translations = DummyTranslations()
def __init__(self, data, errors=(), raw_data=None):
self.data = data
self.errors = list(errors)
self.raw_data = raw_data
def gettext(self, string):
return self._translations.gettext(string)
def ngettext(self, singular, plural, n):
return self._translations.ngettext(singular, plural, n)
dummy_form = dict()
class WTFConverter(Converter):
def make_validator(self, wtf_validator):
def marshmallow_validator(value):
field = DummyField(value)
try:
wtf_validator(dummy_form, field)
except WTFValidationError as err:
raise ValidationError(str(err))
return marshmallow_validator
"""Convert a WTForms validator from wtforms.validators to a
marshmallow validator.
Example::
from wtforms.validators import Length
password = fields.Str(
validate=from_wtforms(Length(min=8, max=100))
)
:param validators: WTForms validators as positional arguments.
"""
from_wtforms = WTFConverter
def test_from_wtforms():
field = fields.Field(
validate=from_wtforms(AnyOf(['red', 'blue']))
)
assert field.deserialize('red') == 'red'
with pytest.raises(UnmarshallingError) as excinfo:
field.deserialize('green')
assert 'Invalid value' in str(excinfo)
def test_from_wtforms_multi():
field = fields.Field(
validate=from_wtforms(
Length(min=4),
NoneOf(['nil', 'null', 'NULL'])
)
)
assert field.deserialize('thisisfine') == 'thisisfine'
with pytest.raises(UnmarshallingError) as excinfo:
field.deserialize('bad')
assert 'Field must be at least 4 characters long' in str(excinfo)
with pytest.raises(UnmarshallingError) as excinfo:
field.deserialize('null')
assert "Invalid value, can't be any of: nil, null, NULL." in str(excinfo)
with pytest.raises(UnmarshallingError) as excinfo:
field.deserialize('nil')
# both errors are returned
assert "Invalid value, can't be any of: nil, null, NULL." in str(excinfo)
assert 'Field must be at least 4 characters long' in str(excinfo)
##### colander #####
from colander import Invalid, ContainsOnly
def _convert_from_colander(colander_validator):
def marshmallow_validator(value):
try:
colander_validator(None, value)
except Invalid as err:
raise ValidationError(err.msg.interpolate())
return marshmallow_validator
def from_colander(*validators):
"""Convert a colander validator from colander to a marshmallow validator.
:param validators: Colander validators as positional arguments.
"""
return [_convert_from_colander(v) for v in validators]
def test_from_colander():
field = fields.Field(
validate=from_colander(ContainsOnly([1]))
)
assert field.deserialize([1]) == [1]
with pytest.raises(UnmarshallingError) as excinfo:
field.deserialize([2])
assert 'One or more of the choices you made was not acceptable' in str(excinfo)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment