Skip to content

Commit d7dde74

Browse files
author
Sylvain MARIE
committed
New empty and non_empty built-in validators in validation_lib. New empty argument in validate. Fixes #31
1 parent 2464e31 commit d7dde74

6 files changed

Lines changed: 79 additions & 12 deletions

File tree

valid8/entry_points_inline.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from valid8.entry_points import Validator, ValidationError, NonePolicy, assert_valid
88
from valid8.validation_lib.types import HasWrongType, IsWrongType
99
from valid8.validation_lib.collections import NotInAllowedValues, TooLong, TooShort, WrongLength, DoesNotContainValue, \
10-
NotSubset, NotSuperset
10+
NotSubset, NotSuperset, NotEmpty, Empty
1111
from valid8.validation_lib.comparables import TooSmall, TooBig, NotEqual
1212

1313
try: # python 3.5+
@@ -136,6 +136,7 @@ def validate(name, # type: str
136136
max_value=None, # type: Any
137137
max_strict=False, # type: bool
138138
length=None, # type: int
139+
empty=None, # type: bool
139140
min_len=None, # type: int
140141
max_len=None, # type: int
141142
custom=None, # type: Callable[[Any], Any]
@@ -169,6 +170,7 @@ def validate(name, # type: str
169170
:param min_strict: if True, only values strictly greater than `min_value` will be accepted
170171
:param max_value: an optional maximum value
171172
:param max_strict: if True, only values strictly lesser than `max_value` will be accepted
173+
:param empty: if `True` should be empty, if `False` should be non-empty. Default: `None` (not checked)
172174
:param length: an optional strict length
173175
:param min_len: an optional minimum length
174176
:param max_len: an optional maximum length
@@ -261,6 +263,15 @@ def validate(name, # type: str
261263
if not value <= max_value:
262264
raise TooBig(wrong_value=value, max_value=max_value, strict=False)
263265

266+
if empty:
267+
# inlined version of empty() without 'return True'
268+
if len(value) > 0:
269+
raise NotEmpty(wrong_value=value)
270+
elif empty is not None:
271+
# inlined version of not_empty() without 'return True'
272+
if len(value) == 0:
273+
raise Empty(wrong_value=value)
274+
264275
if length is not None:
265276
# inlined version of has_length() without 'return True'
266277
if len(value) != length:

valid8/tests/readme/test_readme_combining.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,11 @@ def test_unused_pytypes():
117117
from pytypes import typechecked, InputTypeError
118118

119119
# for value checking
120-
from valid8 import validate_io, minlens, gt
120+
from valid8 import validate_io, non_empty, gt
121121

122122
from ._tests_pep484 import create_for_test_unused_pytypes
123123
build_house = create_for_test_unused_pytypes()
124-
build_house = validate_io(name=minlens(0), surface=gt(0))(build_house)
124+
build_house = validate_io(name=non_empty, surface=gt(0))(build_house)
125125
build_house = typechecked(build_house)
126126

127127
build_house('test', 12, 2) # validation OK

valid8/tests/test_entry_points_inline.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22

33
import pytest
4-
from valid8 import ValidationError, validate, validator
4+
from valid8 import ValidationError, validate, validator, NotEmpty, Empty
55

66
try:
77
from math import isfinite
@@ -230,6 +230,20 @@ def __len__(self):
230230
validate('Foo()', Foo(), min_len=0, max_len=10)
231231

232232

233+
def test_empty_not_empty():
234+
validate('x', [], empty=True)
235+
236+
with pytest.raises(ValidationError) as exc_info:
237+
validate('x', [1], empty=True)
238+
assert isinstance(exc_info.value.validation_outcome, NotEmpty)
239+
240+
validate('x', [1], empty=False)
241+
242+
with pytest.raises(ValidationError) as exc_info:
243+
validate('x', [], empty=False)
244+
assert isinstance(exc_info.value.validation_outcome, Empty)
245+
246+
233247
@pytest.mark.skipif(sys.version_info < (3, 0), reason="type hints not supported in python 2")
234248
def test_function_setter_name_in_valid8_error_message():
235249
""" Tests that the correct function name appears in the valid8 error message """

valid8/tests/validation_lib/test_validators_collections.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from mini_lambda import make_lambda_friendly_method, _, x
44
from valid8 import on_each_, is_even, maxlen, on_all_, is_subset, is_superset, is_in, Failure, minlen, TooShort, \
5-
TooLong, length_between, LengthNotInRange, lt, contains, has_length, WrongLength
5+
TooLong, length_between, LengthNotInRange, lt, contains, has_length, WrongLength, empty, NotEmpty, non_empty, Empty
66

77

88
def test_is_in():
@@ -82,11 +82,18 @@ def test_maxlen():
8282
maxlen(1)(['a', 'a'])
8383

8484

85-
def test_maxlens():
86-
""" tests that the maxlens() function works """
87-
with pytest.raises(TooLong):
88-
maxlens(1)(['a'])
89-
assert maxlens(3)(['a', 'a'])
85+
def test_empty():
86+
""" tests that the empty() function works """
87+
assert empty([])
88+
with pytest.raises(NotEmpty):
89+
empty(['a', 'a'])
90+
91+
92+
def test_nonempty():
93+
""" tests that the non_empty() function works """
94+
assert non_empty(['a', 'a'])
95+
with pytest.raises(Empty):
96+
non_empty([])
9097

9198

9299
def test_length_between():

valid8/validation_lib/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .types import HasWrongType, IsWrongType, instance_of, subclass_of
22
from .collections import TooLong, TooShort, minlen, maxlen, WrongLength, has_length,\
33
LengthNotInRange, length_between, NotInAllowedValues, is_in, NotSubset, is_subset, DoesNotContainValue, contains,\
4-
NotSuperset, is_superset, InvalidItemInSequence, on_all_, on_each_
4+
NotSuperset, is_superset, InvalidItemInSequence, on_all_, on_each_, non_empty, Empty, empty, NotEmpty
55
from .comparables import NotEqual, TooSmall, gt, gts, TooBig, lt, lts, NotInRange, between
66
from .numbers import IsNotEven, is_even, IsNotOdd, is_odd, is_multiple_of, IsNotMultipleOf
77

@@ -10,7 +10,8 @@
1010
'types', 'collections', 'comparables', 'numbers',
1111
# symbols
1212
'HasWrongType', 'IsWrongType', 'instance_of', 'subclass_of',
13-
'TooLong', 'TooShort', 'minlen', 'maxlen', 'WrongLength', 'has_length', 'LengthNotInRange',
13+
'TooLong', 'TooShort', 'minlen', 'maxlen', 'WrongLength', 'has_length',
14+
'non_empty', 'Empty', 'empty', 'NotEmpty', 'LengthNotInRange',
1415
'length_between', 'NotInAllowedValues', 'is_in', 'NotSubset', 'is_subset', 'DoesNotContainValue', 'contains',
1516
'NotSuperset', 'is_superset', 'InvalidItemInSequence', 'on_all_', 'on_each_',
1617
'NotEqual', 'TooSmall', 'gt', 'gts', 'TooBig', 'lt', 'lts', 'NotInRange', 'between',

valid8/validation_lib/collections.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,40 @@
77
from valid8.base import Failure, WrappingFailure, result_is_success, get_callable_name
88

99

10+
class Empty(Failure, ValueError):
11+
""" Custom Failure raised by non_empty """
12+
def __init__(self, wrong_value):
13+
help_msg = 'len(x) > 0 does not hold for x={wrong_value}'
14+
super(Empty, self).__init__(wrong_value=wrong_value, help_msg=help_msg)
15+
16+
17+
def non_empty(x):
18+
"""
19+
'non empty' validation function. Raises a `Empty` error in case of validation failure.
20+
"""
21+
if len(x) > 0:
22+
return True
23+
else:
24+
raise Empty(wrong_value=x)
25+
26+
27+
class NotEmpty(Failure, ValueError):
28+
""" Custom Failure raised by non_empty """
29+
def __init__(self, wrong_value):
30+
help_msg = 'len(x) == 0 does not hold for x={wrong_value}'
31+
super(NotEmpty, self).__init__(wrong_value=wrong_value, help_msg=help_msg)
32+
33+
34+
def empty(x):
35+
"""
36+
'is empty' validation function. Raises a `NotEmpty` error in case of validation failure.
37+
"""
38+
if len(x) == 0:
39+
return True
40+
else:
41+
raise NotEmpty(wrong_value=x)
42+
43+
1044
class TooShort(Failure, ValueError):
1145
""" Custom Failure raised by minlen """
1246
def __init__(self, wrong_value, min_length):

0 commit comments

Comments
 (0)