def test_validator_context_manager(): """ Tests the validation context manager """ # nominal surf = 2 with validator('surface', surf) as v: v.alid = surf > 0 and isfinite(surf) # wrong value (no inner exception) surf = -1 with pytest.raises(ValidationError) as exc_info: with validator('surface', surf) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert str(e) == "Error validating [surface=-1]. " \ "InvalidValue: Function [v.alid = surf > 0 and isfinite(surf)] returned [False] for value -1." # wrong type (inner exception) with pytest.raises(ValidationError) as exc_info: surf = 1j with validator('surface', surf) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value with pytest.raises(TypeError) as typ_err_info: 1j > 0 t = typ_err_info.value assert str(e) == "Error validating [surface=1j]. " \ "InvalidType: Function [v.alid = surf > 0 and isfinite(surf)] raised %s: %s" \ "" % (t.__class__.__name__, t)
def test_readme_usage_validator(): """ Tests that the example under index/usage/validation works """ surf = -1 with pytest.raises(ValidationError) as exc_info: with validator('surface', surf) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert str(e) == "Error validating [surface=-1]. " \ "InvalidValue: Function [v.alid = surf > 0 and isfinite(surf)] returned [False] for value -1." surf = 1j with pytest.raises(ValidationError) as exc_info: with validator('surface', surf) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert str(e).startswith( "Error validating [surface=1j]. " "InvalidType: Function [v.alid = surf > 0 and isfinite(surf)] raised " "TypeError:" ) # the typeerror exact message varies across python versions # alternate naming surf = -1 with pytest.raises(ValidationError) as exc_info: with validator('surface', surf) as r: r.esults = surf > 0 and isfinite(surf) e = exc_info.value assert str(e) == "Error validating [surface=-1]. " \ "InvalidValue: Function [r.esults = surf > 0 and isfinite(surf)] returned [False] for value -1." # type validation surf = 1j with pytest.raises(ValidationError) as exc_info: with validator('surface', surf, instance_of=int) as v: v.alid = surf > 0 e = exc_info.value assert str(e) == "Error validating [surface=1j]. " \ "HasWrongType: Value should be an instance of %r. Wrong value: 1j." % int from valid8 import assert_instance_of with pytest.raises(ValidationError) as exc_info: with validator('surface', surf) as v: assert_instance_of(surf, int) v.alid = surf > 0 e = exc_info.value assert str(e) == "Error validating [surface=1j]. " \ "HasWrongType: Value should be an instance of %r. Wrong value: 1j." % int
def with_validator_boolean_tester(t): from valid8 import validator from valid8.validation_lib import instance_of with validator('t', t, instance_of=tuple) as v: v.alid = len(t) == 2 \ and instance_of(t[0], Real) and (0 <= t[0] <= 1) \ and instance_of(t[1], str) and len(t[1]) == 3 and t[1].islower()
def test_readme_usage_validator_customization(): surf = 1j # (A) custom error message (exception is still a ValidationError) with pytest.raises(ValidationError) as exc_info: with validator( 'surface', surf, help_msg="Surface should be a finite positive integer") as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert str(e).startswith( "Surface should be a finite positive integer. Error validating [surface=1j]. " "InvalidType: Function [v.alid = surf > 0 and isfinite(surf)] raised " "TypeError:" ) # we do not provide the full string as it changes across python versions # (B) custom error types (recommended to provide unique applicative errors) class InvalidSurface(ValidationError): help_msg = 'Surface should be a positive integer' with pytest.raises(ValidationError) as exc_info: with validator('surface', surf, error_type=InvalidSurface) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert isinstance(e, InvalidSurface) # (C) custom error types with templating class InvalidSurface(ValidationError): help_msg = 'Surface should be > {minimum}, found {var_value}' with pytest.raises(ValidationError) as exc_info: with validator('surface', surf, error_type=InvalidSurface, minimum=0) as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert isinstance(e, InvalidSurface) assert str(e).startswith( "Surface should be > 0, found 1j. Error validating [surface=1j]. " "InvalidType: Function [v.alid = surf > 0 and isfinite(surf)] raised " "TypeError:")
def with_validator(s): from valid8 import validator with validator('s', s, instance_of=str) as v: v.alid = (len(s) > 0) and s.islower()
def test_readme_usage_customization(): surf = -1 # (A) custom error message (exception is still a ValidationError) # with pytest.raises(ValidationError) as exc_info: # validate('surface', surf, instance_of=int, min_value=0, # help_msg="Surface should be a positive integer") # e = exc_info.value # assert str(e) == "Surface should be a positive integer. Error validating [surface=-1]. " \ # "TooSmall: x >= 0 does not hold for x=-1. Wrong value: -1." # (A) custom error message (exception is still a ValidationError) with pytest.raises(ValidationError) as exc_info: with validator( 'surface', surf, help_msg="Surface should be a finite positive integer") as v: v.alid = surf > 0 and isfinite(surf) e = exc_info.value assert str(e) == "Surface should be a finite positive integer. Error validating [surface=-1]. " \ "InvalidValue: Function [v.alid = surf > 0 and isfinite(surf)] returned [False] for value -1." # (B) custom error types (recommended to provide unique applicative errors) class InvalidSurface(ValidationError): help_msg = 'Surface should be a positive integer' with pytest.raises(ValidationError) as exc_info: validate('surface', surf, instance_of=int, min_value=0, error_type=InvalidSurface) e = exc_info.value assert isinstance(e, InvalidSurface) assert str(e) == "Surface should be a positive integer. " \ "Error validating [surface=-1]. " \ "TooSmall: x >= 0 does not hold for x=-1. Wrong value: -1." # (C) custom error types with templating class InvalidSurface(ValidationError): help_msg = 'Surface should be > {minimum}, found {var_value}' with pytest.raises(ValidationError) as exc_info: validate('surface', surf, instance_of=int, min_value=0, error_type=InvalidSurface, minimum=0) e = exc_info.value assert isinstance(e, InvalidSurface) assert type(e).__name__ == "InvalidSurface[ValueError]" assert str(e) == "Surface should be > 0, found -1. Error validating [surface=-1]. " \ "TooSmall: x >= 0 does not hold for x=-1. Wrong value: -1." # (D) ValueError/TypeError with pytest.raises(ValidationError) as exc_info: validate('surface', -1, instance_of=int, min_value=0) e = exc_info.value assert str( e ) == "Error validating [surface=-1]. TooSmall: x >= 0 does not hold for x=-1. Wrong value: -1." assert repr( e.__class__ ) == "<class 'valid8.entry_points.ValidationError[ValueError]'>" with pytest.raises(ValidationError) as exc_info: validate('surface', 1j, instance_of=int, min_value=0) e = exc_info.value assert repr(e.__class__ ) == "<class 'valid8.entry_points.ValidationError[TypeError]'>"
def test_readme_examples_4(): """ Tests that the example 4 provided in the documentation works (list of custom tuples) """ l = [(1, 'ras'), (0.2, 'abc')] # ---- inline 1 from valid8 import validate # first validate the main type validate('l', l, instance_of=list) for i, v in enumerate(l): # each item is a tuple of size 2 validate('l[%s]' % i, l[i], instance_of=tuple, length=2) # the first element is a float between 0 and 1 validate('l[%s][0]' % i, l[i][0], instance_of=Real, min_value=0, max_value=1) # the second element is a lowercase string of size 3 validate('l[%s][1]' % i, l[i][1], instance_of=str, length=3, equals=l[i][1].lower()) # ---- inline 2 from valid8 import validator from valid8.validation_lib import instance_of l = [(1, 'ras'), (0.2, 'abc')] # all at once with validator('l', l, instance_of=list) as v: v.alid = all( # each item is a tuple of size 2 instance_of(item, tuple) and len(item) == 2 # the first element is a float between 0 and 1 and instance_of(item[0], Real) and (0 <= item[0] <= 1) # the second element is a lowercase string of size 3 and instance_of(item[1], str) and len(item[1]) == 3 and item[1].islower() for item in l) # custom validation function def check_valid_tuple(tup): """ custom validation function - here in 'failure raiser' style (returning nothing) """ # each item is a tuple of size 2 if not isinstance(tup, tuple): raise TypeError('item should be a tuple') if len(tup) != 2: raise ValueError('tuple length should be 2') # the first element is a float between 0 and 1 if not isinstance(tup[0], Real): raise TypeError('first element should be a Real') if not (0 <= tup[0] <= 1): raise ValueError('first element should be between 0 and 1') # the second element is a lowercase string of size 3 if not isinstance(tup[1], str): raise TypeError('second element should be a string') if not (len(tup[1]) == 3 and tup[1].islower()): raise ValueError( 'second element should be a lowercase string of length 3') from valid8 import validate, validation # first validate the main type validate('l', l, instance_of=list) # then validate (and use) the contents for i, v in enumerate(l): # each item is a valid tuple with validation('l[%s]' % i, l[i]): check_valid_tuple(l[i]) # here you can actually USE the current item # ---- function input from valid8 import validate_arg, and_ from valid8.validation_lib import instance_of, on_all_, on_each_, has_length, between @validate_arg( 'l', instance_of(list), on_all_( instance_of(tuple), has_length(2), # each item is a tuple of size 2 on_each_( and_(instance_of(Real), between( 0, 1)), # the first element is a float between 0 and 1 and_( instance_of(str), has_length(3) ), # the 2d element is a string of len 3 BUT we cannot check lowercase ))) def my_function(l): pass l = [(1, 'ras'), (0.2, 'aBc')] # we cannot check lowercase my_function(l) # much better: from valid8 import validate_arg, ValidationFailure from valid8.validation_lib import instance_of, on_all_, HasWrongType, WrongLength, NotInRange def is_valid_tuple(t): """ Custom validation function. We could also provide a callable """ # (a) each item is a tuple of size 2 # --you can reuse an entire method from the built-in lib when it supports direct calling mode instance_of(t, tuple) # --otherwise you can reuse a failure class, there are many if len(t) != 2: raise WrongLength(t, ref_length=2) # (b) the first element is a float between 0 and 1 if not isinstance(t[0], Real): raise HasWrongType(t[0], Real) if not (0 <= t[0] <= 1): raise NotInRange(t[0], min_value=0, max_value=1) # (c) the second element is a lowercase string of size 3 instance_of(t[1], str) if len(t[1]) != 3: raise WrongLength(t[1], ref_length=3) # -- finally you can write custom ValidationFailure types if not t[1].islower(): raise NotLowerCase(t[1]) class NotLowerCase(ValidationFailure, ValueError): """ Example custom exception class used in custom validation function. `ValidationFailure` base class provides some mechanisms to easily build the help message (same mechanisms than ValidationError)""" help_msg = "Value is not a lowercase string: {wrong_value}" @validate_arg('l', instance_of(list), on_all_(is_valid_tuple)) def my_function(l): pass l = [(1, 'ras'), (0.2, 'abc')] my_function(l) # ---- mini_lambda from valid8 import validate_arg from valid8.validation_lib import instance_of, on_all_ # just for fun: we create our custom mini_lambda variable named 't' from mini_lambda import InputVar, Len, Isinstance t = InputVar('t', tuple) @validate_arg( 'l', instance_of(list), on_all_( # each item is a tuple of size 2 instance_of(tuple), Len(t) == 2, # the first element is a float between 0 and 1 Isinstance(t[0], Real), (0 <= t[0]) & (t[0] <= 1), # the 2d element is a lowercase string of len 3 Isinstance(t[1], str), Len(t[1]) == 3, t[1].islower())) def my_function(l): pass l = [(1, 'ras'), (0.2, 'abc')] my_function(l)
def with_validator(x): from valid8 import validator with validator('x', x, instance_of=Integral) as v: v.alid = x >= 0
def inline_validator_custom_boolean(t, custom): from valid8 import validator with validator('t', t) as v: v.alid = custom(t)