-
Notifications
You must be signed in to change notification settings - Fork 12
Custom Validator
guyskk edited this page Mar 29, 2020
·
5 revisions
validator()
decorater is used to create validator, and it can make you validator support common parameters default
, optional
, desc
, invalid_to
, invalid_to_default
and optional object
.
You can control the validor accept and output value types by accept
and output
parameter:
- accept (
str
|object
|(str,object)
):-
str
: the validator accept only string, treat both None and empty string as None -
object
: the validator accept only object -
(str,object)
: (default) the validator accept both string and object, treat both None and empty string as None
-
- output (
str
|object
|(str,object)
):-
str
: (default) the validator always output string, convert None to empty string -
object
: the validator always output object -
(str, object)
: the validator can output both string and object, and has anobject
parameter to control which to output. To reduce conflict, theobject
parameter will rename tooutput_object
in validator's signature.
-
A general custom validator:
from validr import T, validator
@validator(accept=(str, object), output=(str, object))
def xxx_validator(compiler, items=None, output_object=False, some_param=None):
"""Custom validator
Params:
compiler: can be used for compile inner schema
items: optional, and can only be scalar type, passed by schema in `T.validator(items)` form
output_object: control whether output object, only passed when `output=(str, object)`
some_param: other params
Returns:
validate function
"""
def validate(value):
"""Validate function
Params:
value: data to be validate
Returns:
valid value or converted value
Raises:
Invalid: value invalid
"""
try:
# validate/convert the value
except Exception:
# raise Invalid('invalid xxx')
if output_object:
# return python object
else:
# return string
return validate
# use custom validators
compiler = Compiler(validators={
# name: validator
'xxx': xxx_validator,
})
Example, time interval validator:
from validr import T, validator, SchemaError, Invalid, Compiler
UNITS = {'s':1, 'm':60, 'h':60*60, 'd':24*60*60}
def to_seconds(t):
return int(t[:-1]) * UNITS[t[-1]]
@validator(accept=str, output=object)
def interval_validator(compiler, min='0s', max='365d'):
"""Time interval validator, convert value to seconds
Supported time units:
s: seconds, eg: 10s
m: minutes, eg: 10m
h: hours, eg: 1h
d: days, eg: 7d
"""
try:
min = to_seconds(min)
except (IndexError,KeyError,ValueError):
raise SchemaError('invalid min value') from None
try:
max = to_seconds(max)
except (IndexError,KeyError,ValueError):
raise SchemaError('invalid max value') from None
def validate(value):
try:
value = to_seconds(value)
except (IndexError,KeyError,ValueError):
raise Invalid("invalid interval") from None
if value < min:
raise Invalid("interval must >= {} seconds".format(min))
if value > max:
raise Invalid("interval must <= {} seconds".format(max))
return value
return validate
compiler = Compiler(validators={"interval": interval_validator})
f = compiler.compile(T.interval.max('8h'))
>>> f('15m')
900
>>> f('15x')
...
validr._exception.Invalid: invalid interval, value=15x
>>> f('10h')
...
validr._exception.Invalid: interval must <= 28800 seconds, value=10h
>>> f = compiler.compile(T.interval.default('5m'))
>>> f(None)
300
>>> compiler.compile(T.interval.max('12x'))
...
validr._exception.SchemaError: invalid max value, schema=interval.max('12x')
from validr import T, Compiler, create_re_validator
regex_time = r'([01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d'
time_validator = create_re_validator("time", regex_time)
compiler = Compiler(validators={"time": time_validator})
f = compiler.compile(T.time.default("00:00:00"))
>>> f("12:00:00")
'12:00:00'
>>> f("12:00:123")
...
validr._exception.Invalid: invalid time, value=12:00:123
>>> f(None)
'00:00:00'
>>>