Skip to content

Commit 2418ab8

Browse files
author
Jack Saunders
committed
bounds checking for Integer
1 parent 901d7ef commit 2418ab8

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

kim/field.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
'none_not_allowed': 'This field cannot be null',
3131
'invalid_choice': 'invalid choice',
3232
'duplicates': 'duplicates found',
33+
'out_of_bounds': 'value out of allowed range',
3334
}
3435

3536

@@ -296,6 +297,18 @@ class UserMapper(Mapper):
296297
serialize_pipeline = StringSerializePipeline
297298

298299

300+
class IntegerFieldOpts(FieldOpts):
301+
"""Custom FieldOpts class that provides additional config options for
302+
:class:`.Integer`.
303+
304+
"""
305+
306+
def __init__(self, **kwargs):
307+
self.max = kwargs.pop('max', None)
308+
self.min = kwargs.pop('min', None)
309+
super(IntegerFieldOpts, self).__init__(**kwargs)
310+
311+
299312
class Integer(Field):
300313
""":class:`.Integer` represents a value that must be valid
301314
when passed to int()
@@ -312,6 +325,7 @@ class UserMapper(Mapper):
312325
313326
"""
314327

328+
opts_class = IntegerFieldOpts
315329
marshal_pipeline = IntegerMarshalPipeline
316330
serialize_pipeline = IntegerSerializePipeline
317331

kim/pipelines/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def run(self, **opts):
137137
return session.output
138138

139139

140-
@pipe()
140+
@pipe(run_if_none=True)
141141
def get_data_from_name(session):
142142
"""extracts a specific key from data using field.name. This pipe is
143143
typically used as the entry point to a chain of input pipes.

kim/pipelines/numeric.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,29 @@ def is_valid_integer(session):
2828
raise session.field.invalid(error_type='type_error')
2929

3030

31+
@pipe()
32+
def bounds_check(session):
33+
"""pipe used to determine if a value can be coerced to an int
34+
35+
:param session: Kim pipeline session instance
36+
37+
"""
38+
39+
max_ = session.field.opts.max
40+
min_ = session.field.opts.min
41+
42+
if max_ is not None and session.data > max_:
43+
raise session.field.invalid(error_type='out_of_bounds')
44+
if min_ is not None and session.data < min_:
45+
raise session.field.invalid(error_type='out_of_bounds')
46+
47+
return session.data
48+
49+
3150
class IntegerMarshalPipeline(MarshalPipeline):
3251

3352
validation_pipes = \
34-
[is_valid_integer, is_valid_choice] + MarshalPipeline.validation_pipes
53+
[is_valid_integer, is_valid_choice, bounds_check] + MarshalPipeline.validation_pipes
3554

3655

3756
class IntegerSerializePipeline(SerializePipeline):

tests/test_pipelines/test_numeric.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ def test_marshal_read_only_integer():
8181
assert output == {}
8282

8383

84+
def test_marshal_default():
85+
86+
field = Integer(name='name', default=5)
87+
88+
output = {}
89+
mapper_session = get_mapper_session(data={}, output=output)
90+
91+
field.marshal(mapper_session)
92+
assert output == {'name': 5}
93+
94+
8495
def test_is_valid_choice():
8596

8697
field = Integer(name='type', choices=[1, 2])
@@ -94,6 +105,24 @@ def test_is_valid_choice():
94105
assert output == {'type': 1}
95106

96107

108+
def test_min_max():
109+
110+
field = Integer(name='age', min=20, max=35)
111+
output = {}
112+
113+
mapper_session = get_mapper_session(data={'age': 15}, output=output)
114+
with pytest.raises(FieldInvalid):
115+
field.marshal(mapper_session)
116+
117+
mapper_session = get_mapper_session(data={'age': 40}, output=output)
118+
with pytest.raises(FieldInvalid):
119+
field.marshal(mapper_session)
120+
121+
mapper_session = get_mapper_session(data={'age': 25}, output=output)
122+
field.marshal(mapper_session)
123+
assert output == {'age': 25}
124+
125+
97126
def test_is_valid_decimal_pipe():
98127
"""test piping data through is_valid_decimal.
99128
"""

0 commit comments

Comments
 (0)