Skip to content

Commit a91e2d5

Browse files
author
nxexox
committed
bug fixing. V 0.1.6
1 parent 5fbfbbd commit a91e2d5

File tree

6 files changed

+53
-40
lines changed

6 files changed

+53
-40
lines changed

docs/release-notes.md

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ Medium version numbers (0.x.0) may include API changes, in line with the [deprec
88

99
Major version numbers (x.0.0) are reserved for substantial project milestones.
1010

11+
### 0.1.6
12+
13+
**Date**: [18th December 2018].
14+
15+
* Fix internal logic on validation field binding.
16+
* Fix settings internal validators on fields.
17+
1118
### 0.1.5
1219

1320
**Date**: [12th December 2018].

rest_framework/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
__/ |
99
|___/
1010
"""
11-
VERSION = (0, 1, 5)
11+
VERSION = (0, 1, 6)
1212

1313
__title__ = 'Python-Rest-Framework'
1414
__author__ = 'Deys Timofey'

rest_framework/serializers/fields.py

+21-17
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
"""
55
import re
6-
import collections
6+
import typing
77
import datetime
88
import json
99

@@ -48,7 +48,7 @@ def get_attribute(obj, attr_name):
4848
4949
"""
5050
# Search attribute.
51-
if isinstance(obj, collections.Mapping):
51+
if isinstance(obj, typing.Mapping):
5252
attr = obj[attr_name]
5353
else:
5454
attr = getattr(obj, attr_name)
@@ -305,6 +305,10 @@ def run_validation(self, data):
305305
# First, we validate to be bound.
306306
is_empty, data = self.validate_empty_values(data)
307307

308+
# If empty data and field not required.
309+
if is_empty and not self.required:
310+
return data
311+
308312
# Process raw data.
309313
value = self.to_internal_value(data)
310314
# Run validators.
@@ -358,16 +362,16 @@ def __init__(self, min_length=None, max_length=None, trim_whitespace=False, allo
358362
359363
"""
360364
super().__init__(*args, **kwargs)
361-
self.max_length = max_length
362-
self.min_length = min_length
365+
self.max_length = max_length if max_length is None else int(max_length)
366+
self.min_length = min_length if min_length is None else int(min_length)
363367
self.trim_whitespace = trim_whitespace
364368
self.allow_blank = allow_blank
365369

366370
# Added validators.
367-
if self.max_length:
371+
if self.max_length is not None:
368372
message = self.error_messages['max_length'].format(max_length=self.max_length)
369373
self.validators.append(MaxLengthValidator(max_length, message=message))
370-
if self.min_length:
374+
if self.min_length is not None:
371375
message = self.error_messages['min_length'].format(min_length=self.min_length)
372376
self.validators.append(MinLengthValidator(self.min_length, message=message))
373377

@@ -444,10 +448,10 @@ def __init__(self, min_value=None, max_value=None, *args, **kwargs):
444448
self.max_value = max_value if max_value is None else int(max_value)
445449

446450
# Added validators.
447-
if self.min_value:
451+
if self.min_value is not None:
448452
message = self.error_messages['min_value'].format(min_value=self.min_value)
449453
self.validators.append(MinValueValidator(self.min_value, message=message))
450-
if self.max_value:
454+
if self.max_value is not None:
451455
message = self.error_messages['max_value'].format(max_value=self.max_value)
452456
self.validators.append(MaxValueValidator(self.max_value, message=message))
453457

@@ -508,14 +512,14 @@ def __init__(self, min_value=None, max_value=None, *args, **kwargs):
508512
509513
"""
510514
super().__init__(*args, **kwargs)
511-
self.min_value = min_value if min_value is None else int(min_value)
512-
self.max_value = max_value if max_value is None else int(max_value)
515+
self.min_value = min_value if min_value is None else float(min_value)
516+
self.max_value = max_value if max_value is None else float(max_value)
513517

514518
# Added validators.
515-
if self.min_value:
519+
if self.min_value is not None:
516520
message = self.error_messages['min_value'].format(min_value=self.min_value)
517521
self.validators.append(MinValueValidator(self.min_value, message=message))
518-
if self.max_value:
522+
if self.max_value is not None:
519523
message = self.error_messages['max_value'].format(max_value=self.max_value)
520524
self.validators.append(MaxValueValidator(self.max_value, message=message))
521525

@@ -688,8 +692,8 @@ def __init__(self, child=None, min_length=None, max_length=None, allow_empty=Fal
688692
"""
689693
super().__init__(*args, **kwargs)
690694
self.child = child or self.child
691-
self.min_length = min_length
692-
self.max_length = max_length
695+
self.min_length = min_length if min_length is None else int(min_length)
696+
self.max_length = max_length if max_length is None else int(max_length)
693697
self.allow_empty = bool(allow_empty)
694698

695699
# Check field `child`.
@@ -699,10 +703,10 @@ def __init__(self, child=None, min_length=None, max_length=None, allow_empty=Fal
699703
self.child.bind(field_name='', parent=self) # Bind child field.
700704

701705
# Added validators.
702-
if self.max_length:
706+
if self.max_length is not None:
703707
message = self.error_messages['max_length'].format(max_length=self.max_length)
704708
self.validators.append(MaxLengthValidator(max_length, message=message))
705-
if self.min_length:
709+
if self.min_length is not None:
706710
message = self.error_messages['min_length'].format(min_length=self.min_length)
707711
self.validators.append(MinLengthValidator(self.min_length, message=message))
708712

@@ -721,7 +725,7 @@ def to_internal_value(self, data):
721725
if html.is_html_input(data):
722726
data = html.parse_html_list(data)
723727

724-
if any((isinstance(data, type('')), isinstance(data, collections.Mapping), not hasattr(data, '__iter__'))):
728+
if any((isinstance(data, type('')), isinstance(data, typing.Mapping), not hasattr(data, '__iter__'))):
725729
self.fail('not_a_list', input_type=type(data).__name__)
726730

727731
if not self.allow_empty and len(data) == 0:

rest_framework/serializers/serializers.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55
import copy
66
import inspect
7+
from typing import Mapping
78
from collections import OrderedDict
89

910
import six
@@ -107,7 +108,7 @@ def __init__(self, instance=None, data=None, *args, **kwargs):
107108
"""
108109
super().__init__(*args, **kwargs)
109110
self.instance = instance
110-
if isinstance(data, dict):
111+
if isinstance(data, Mapping):
111112
self.initial_data = data
112113

113114
def __new__(cls, *args, **kwargs):

rest_framework/tests/test_fields.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
RequiredValidator, MaxValueValidator, MinValueValidator, MinLengthValidator, MaxLengthValidator
2121
)
2222

23-
from .serializers_for_tests import SerializerMethodFieldDefault, SerializerMethodFieldSingle
23+
from rest_framework.tests.serializers_for_tests import SerializerMethodFieldDefault, SerializerMethodFieldSingle
2424

2525

2626
class BaseFieldTestCase(TestCase):
@@ -481,7 +481,7 @@ class CharFieldTest(BaseFieldTestCase):
481481
{'data': {'data': 123}, 'return': '123'},
482482
{'data': {'data': 'qwe'}, 'return': 'qwe'},
483483
{'data': {'data': None}, 'exceptions': (ValidationError,)},
484-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)},
484+
{'data': {'data': None}, 'params': {'required': False}, 'return': None},
485485
{'data': {'data': ''}, 'params': {'allow_blank': False}, 'exceptions': (ValidationError,)},
486486
{'data': {'data': ''}, 'params': {'allow_blank': True}, 'return': ''},
487487
{'data': {'data': ' '}, 'params': {'allow_blank': True, 'trim_whitespace': True}, 'return': ''},
@@ -758,7 +758,7 @@ class TestTimeField(BaseFieldTestCase):
758758
{'data': {'data': datetime.time()}, 'return': datetime.time()},
759759
{'data': {'data': datetime.time(10, 10)}, 'return': datetime.time(10, 10)},
760760
{'data': {'data': None}, 'exceptions': (ValidationError,)},
761-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)},
761+
{'data': {'data': None}, 'params': {'required': False}, 'return': None},
762762
{'data': {'data': None}, 'params': {'default': datetime.time()}, 'return': datetime.time()},
763763
) # Cases, to test the performance of `.run_validation()`.
764764

@@ -801,7 +801,7 @@ class TestDateField(BaseFieldTestCase):
801801
{'data': {'data': datetime.datetime.now()}, 'exceptions': (ValidationError,)},
802802
{'data': {'data': '2018-10'}, 'params': {'input_format': '%Y-%m'}, 'return': datetime.date(2018, 10, 1)},
803803
{'data': {'data': None}, 'exceptions': (ValidationError,)},
804-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)},
804+
{'data': {'data': None}, 'params': {'required': False}, 'return': None},
805805
{'data': {'data': None}, 'params': {'default': datetime.date(2018, 1, 1)}, 'return': datetime.date(2018, 1, 1)},
806806
) # Cases, to test the performance of `.run_validation()`.
807807

@@ -847,7 +847,7 @@ class TestDateTimeField(BaseFieldTestCase):
847847
{'data': {'data': __now_for_test.strftime(DateTimeField.input_format)}, 'return': __now_for_test},
848848
{'data': {'data': '2018-10'}, 'params': {'input_format': '%Y-%m'}, 'return': datetime.datetime(2018, 10, 1)},
849849
{'data': {'data': None}, 'exceptions': (ValidationError,)},
850-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)},
850+
{'data': {'data': None}, 'params': {'required': False}, 'return': None},
851851
{'data': {'data': None}, 'params': {'default': datetime.datetime(2018, 1, 1)}, 'return': datetime.datetime(2018, 1, 1)},
852852
) # Cases, to test the performance of `.run_validation()`.
853853

@@ -897,7 +897,7 @@ class TestJsonField(BaseFieldTestCase):
897897
{'data': {'data': 'asd'}, 'exceptions': (ValidationError,)},
898898
{'data': {'data': 123}, 'exceptions': (ValidationError,)},
899899
{'data': {'data': None}, 'exceptions': (ValidationError,)},
900-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)}, # TODO: FIXME
900+
{'data': {'data': None}, 'params': {'required': False}, 'return': None}, # TODO: FIXME
901901
) # Cases, to test the performance of `.run_validation()`.
902902

903903

@@ -941,7 +941,7 @@ class TestDictField(BaseFieldTestCase):
941941
{'data': {'data': 'asd'}, 'exceptions': (ValidationError,)},
942942
{'data': {'data': 123}, 'exceptions': (ValidationError,)},
943943
{'data': {'data': None}, 'exceptions': (ValidationError,)},
944-
{'data': {'data': None}, 'params': {'required': False}, 'exceptions': (ValidationError,)}, # TODO: FIXME
944+
{'data': {'data': None}, 'params': {'required': False}, 'return': None}, # TODO: FIXME
945945
{'data': {'data': {123: [123]}}, 'params': {'child': IntegerField()}, 'exceptions': (ValidationError,)}
946946
) # Cases, to test the performance of `.run_validation()`.
947947

rest_framework/tests/test_serializers.py

+15-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
2. We test the external interface as they should work.
55
66
"""
7-
import collections
7+
# import collections
8+
import typing
89
from unittest import TestCase
910

1011
import six
@@ -311,7 +312,7 @@ def __create_object(self, data):
311312
312313
"""
313314
return type('object', (object,), {
314-
key: self.__create_object(val) if isinstance(val, collections.Mapping) else val
315+
key: self.__create_object(val) if isinstance(val, typing.Mapping) else val
315316
for key, val in six.iteritems(data)
316317
})
317318

@@ -358,10 +359,10 @@ def test_data_serializer(self):
358359
# First we feed him empty data.
359360
ser = self.serializer_class(data=self.__create_params(fullness='empty'))
360361
assert ser.is_valid() is False, '`.is_valid()` must return False.'
361-
assert isinstance(ser.errors, collections.Mapping), \
362+
assert isinstance(ser.errors, typing.Mapping), \
362363
'`.errors` must be dict. Reality: {}.'.format(type(ser.errors))
363364
assert len(ser.errors) > 0, '`.errors` must contain errors.'
364-
assert isinstance(ser.validated_data, collections.Mapping), \
365+
assert isinstance(ser.validated_data, typing.Mapping), \
365366
'`.validated_data` must be dict. Reality: {}.'.format(type(ser.validated_data))
366367
assert len(ser.validated_data) == 0, '`.validated_data` must be empty. Reality: {},'.format(ser.validated_data)
367368

@@ -376,10 +377,10 @@ def test_data_serializer(self):
376377
# Now we feed the data partially.
377378
ser = self.serializer_class(data=self.__create_params(fullness='middle'))
378379
assert ser.is_valid() is False, '`.is_valid()` must return False.'
379-
assert isinstance(ser.errors, collections.Mapping), \
380+
assert isinstance(ser.errors, typing.Mapping), \
380381
'`.errors` must be dict. Reality: {}.'.format(type(ser.errors))
381382
assert len(ser.errors) > 0, '`.errors` must contain errors.'
382-
assert isinstance(ser.validated_data, collections.Mapping), \
383+
assert isinstance(ser.validated_data, typing.Mapping), \
383384
'`.validated_data` must be dict. Reality: {}.'.format(type(ser.validated_data))
384385
assert len(ser.validated_data) == 0, '`.validated_data` must be empty. Reality: {}.'.format(ser.validated_data)
385386

@@ -388,10 +389,10 @@ def test_data_serializer(self):
388389
ser = self.serializer_class(data=data)
389390
# Check logic.
390391
assert ser.is_valid() is True, '`.is_valid()` must return True.'
391-
assert isinstance(ser.errors, collections.Mapping), \
392+
assert isinstance(ser.errors, typing.Mapping), \
392393
'`.errors` must be dict. Reality: {}.'.format(type(ser.errors))
393394
assert len(ser.errors) == 0, '`.errors` must be empty. Reality: {}.'.format(ser.errors)
394-
assert isinstance(ser.validated_data, collections.Mapping), \
395+
assert isinstance(ser.validated_data, typing.Mapping), \
395396
'`.validated_data` must be dict. Reality: {}.'.format(ser.validated_data)
396397
assert len(ser.validated_data) > 0, '`.validated_data` must contain data.'
397398
# We check that all data is returned correctly.
@@ -409,12 +410,12 @@ def test_instance_object_serializer(self):
409410
"""
410411
# First we feed him an empty object.
411412
ser = self.serializer_class(instance=self.__create_object(self.__create_params(fullness='empty')))
412-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}'.format(type(ser.data))
413+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}'.format(type(ser.data))
413414

414415
# Now we feed the data partially.
415416
data = self.__create_params(fullness='middle')
416417
ser = self.serializer_class(instance=self.__create_object(data))
417-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
418+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
418419
for k, v in six.iteritems(ser.data):
419420
if k in data:
420421
assert v == data[k], 'Object attribute `{}` must be `{}`, reality `{}`.'.format(k, v, data[k])
@@ -424,7 +425,7 @@ def test_instance_object_serializer(self):
424425
# Now we feed the data completely.
425426
data = self.__create_params(fullness='full')
426427
ser = self.serializer_class(instance=self.__create_object(data))
427-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
428+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
428429
for k, v in six.iteritems(ser.data):
429430
if k in data:
430431
assert v == data[k], 'Object attribute `{}` must be `{}`, reality `{}`.'.format(k, v, data[k])
@@ -439,12 +440,12 @@ def test_instance_dict_serializer(self):
439440
"""
440441
# First we feed him an empty object..
441442
ser = self.serializer_class(instance=self.__create_params(fullness='empty'))
442-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
443+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
443444

444445
# Now we feed the data partially.
445446
data = self.__create_params(fullness='middle')
446447
ser = self.serializer_class(instance=data)
447-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
448+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
448449
for k, v in six.iteritems(ser.data):
449450
if k in data:
450451
assert v == data[k], 'Object attribute`{}` must be `{}`, reality `{}`.'.format(k, v, data[k])
@@ -454,7 +455,7 @@ def test_instance_dict_serializer(self):
454455
# Now we feed the data completely.
455456
data = self.__create_params(fullness='full')
456457
ser = self.serializer_class(instance=data)
457-
assert isinstance(ser.data, collections.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
458+
assert isinstance(ser.data, typing.Mapping), '`.data` must be dict. Reality: {}.'.format(type(ser.data))
458459
for k, v in six.iteritems(ser.data):
459460
if k in data:
460461
assert v == data[k], 'Object attribute `{}` must be `{}`, reality `{}`.'.format(k, v, data[k])

0 commit comments

Comments
 (0)