Skip to content

Commit 20f0332

Browse files
authored
added method fail into fields. Rename old method fail to fail_field_validation
added method fail into fields. Rename old method fail to fail_field_validation
1 parent 39a09ab commit 20f0332

File tree

5 files changed

+88
-36
lines changed

5 files changed

+88
-36
lines changed

docs/api-guid/fields.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -333,25 +333,25 @@ class ClassNameField(serializers.Field):
333333
### Raising validation errors
334334

335335
Our `ColorField` class above currently does not perform any data validation.
336-
To indicate invalid data, we should raise a `serializers.ValidationError`, like so:
336+
To indicate invalid data, we should raise a `serializers.ValidationError` or call `self.fail(detail, status=400)`, like so:
337337
```python
338338
def to_internal_value(self, data):
339339
if not isinstance(data, six.text_type):
340340
msg = 'Incorrect type. Expected a string, but got %s'
341-
raise ValidationError(msg % type(data).__name__)
341+
raise ValidationError(detail=msg % type(data).__name__)
342342

343343
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
344-
raise ValidationError('Incorrect format. Expected `rgb(#,#,#)`.')
344+
raise ValidationError(detail='Incorrect format. Expected `rgb(#,#,#)`.', status=500)
345345

346346
data = data.strip('rgb(').rstrip(')')
347347
red, green, blue = [int(col) for col in data.split(',')]
348348

349349
if any([col > 255 or col < 0 for col in (red, green, blue)]):
350-
raise ValidationError('Value out of range. Must be between 0 and 255.')
350+
self.fail(detail='Value out of range. Must be between 0 and 255.')
351351

352352
return Color(red, green, blue)
353353
```
354-
The `.fail()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example:
354+
The `.fail_field_validation()` method is a shortcut for raising `ValidationError` that takes a message string from the `error_messages` dictionary. For example:
355355
```python
356356
default_error_messages = {
357357
'incorrect_type': 'Incorrect type. Expected a string, but got {input_type}',
@@ -361,16 +361,16 @@ default_error_messages = {
361361

362362
def to_internal_value(self, data):
363363
if not isinstance(data, six.text_type):
364-
self.fail('incorrect_type', input_type=type(data).__name__)
364+
self.fail_field_validation('incorrect_type', input_type=type(data).__name__)
365365

366366
if not re.match(r'^rgb\([0-9]+,[0-9]+,[0-9]+\)$', data):
367-
self.fail('incorrect_format')
367+
self.fail_field_validation('incorrect_format')
368368

369369
data = data.strip('rgb(').rstrip(')')
370370
red, green, blue = [int(col) for col in data.split(',')]
371371

372372
if any([col > 255 or col < 0 for col in (red, green, blue)]):
373-
self.fail('out_of_range')
373+
self.fail_field_validation('out_of_range')
374374

375375
return Color(red, green, blue)
376376
```

docs/release-notes.md

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ 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+
12+
### 0.3.11
13+
14+
**Date:** [21th January 2020]
15+
16+
* Renaming method `fail` -> `fail_field_validation`.
17+
* Added method `fail(detail, status)` for raise `ValidationError`.
18+
1119
### 0.3.10
1220

1321
**Date:** [17th September 2019]

rest_framework/__init__.py

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

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

rest_framework/serializers/fields.py

+32-19
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,20 @@ def get_validators(self):
158158
"""
159159
return self.default_validators[:]
160160

161-
def fail(self, key, **kwargs):
161+
def fail(self, detail=None, status=400):
162+
"""
163+
We throw a normal error if custom validation error.
164+
165+
:param Union[str, dict] detail: Detail validation error
166+
:param int status: Code for response
167+
168+
:raise AssertionError: If you have not found the key in the `self.error_messages`.
169+
:raise ValidationError: If you find the key in the `self.error_messages`.
170+
171+
"""
172+
raise ValidationError(detail=detail, status=status)
173+
174+
def fail_field_validation(self, key, **kwargs):
162175
"""
163176
We throw a normal error if something went wrong during data processing.
164177
@@ -440,7 +453,7 @@ def run_validation(self, data=None):
440453
"""
441454
if data == '' or (self.trim_whitespace and six.text_type(data).strip() == ''):
442455
if not self.allow_blank:
443-
self.fail('blank')
456+
self.fail_field_validation('blank')
444457
return ''
445458
return super(CharField, self).run_validation(data)
446459

@@ -458,7 +471,7 @@ def to_internal_value(self, data):
458471
"""
459472
# We skip numbers as strings, but bool as strings seems to be a developer error.
460473
if isinstance(data, bool) or not isinstance(data, six.string_types + six.integer_types + (float,)):
461-
self.fail('invalid')
474+
self.fail_field_validation('invalid')
462475

463476
val = six.text_type(data)
464477

@@ -536,12 +549,12 @@ def to_internal_value(self, data):
536549
"""
537550
# We look, do not want us to score a memory?
538551
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
539-
self.fail('max_string_length')
552+
self.fail_field_validation('max_string_length')
540553

541554
try:
542555
data = int(self.re_decimal.sub('', str(data)))
543556
except (ValueError, TypeError):
544-
self.fail('invalid')
557+
self.fail_field_validation('invalid')
545558
return data
546559

547560
def to_representation(self, value):
@@ -612,12 +625,12 @@ def to_internal_value(self, data):
612625
"""
613626
# We look, do not want us to score a memory?
614627
if isinstance(data, six.text_type) and len(data) > self.MAX_STRING_LENGTH:
615-
self.fail('max_string_length')
628+
self.fail_field_validation('max_string_length')
616629

617630
try:
618631
return float(data)
619632
except (TypeError, ValueError):
620-
self.fail('invalid')
633+
self.fail_field_validation('invalid')
621634

622635
def to_representation(self, value):
623636
"""
@@ -676,7 +689,7 @@ def to_internal_value(self, data):
676689
return False
677690
except TypeError: # If the non-hash type came.
678691
pass
679-
self.fail('invalid', input=data)
692+
self.fail_field_validation('invalid', input=data)
680693

681694
def to_representation(self, value):
682695
"""
@@ -744,7 +757,7 @@ def to_internal_value(self, data):
744757
return None
745758
except TypeError: # If the non-hash type came.
746759
pass
747-
self.fail('invalid', input=data)
760+
self.fail_field_validation('invalid', input=data)
748761

749762
def to_representation(self, value):
750763
"""
@@ -874,10 +887,10 @@ def to_internal_value(self, data):
874887
data = html.parse_html_list(data)
875888

876889
if any((isinstance(data, type('')), isinstance(data, Mapping), not hasattr(data, '__iter__'))):
877-
self.fail('not_a_list', input_type=type(data).__name__)
890+
self.fail_field_validation('not_a_list', input_type=type(data).__name__)
878891

879892
if not self.allow_empty and len(data) == 0:
880-
self.fail('empty')
893+
self.fail_field_validation('empty')
881894

882895
return [self.child.run_validation(item) for item in data]
883896

@@ -946,7 +959,7 @@ def to_internal_value(self, data):
946959

947960
# Check on the datetime object.
948961
if isinstance(data, datetime.datetime):
949-
self.fail('datetime')
962+
self.fail_field_validation('datetime')
950963

951964
# Check on the date object.
952965
if isinstance(data, datetime.date):
@@ -962,7 +975,7 @@ def to_internal_value(self, data):
962975
return parsed.date()
963976

964977
# Throw exception.
965-
self.fail('invalid', format=data)
978+
self.fail_field_validation('invalid', format=data)
966979

967980
def to_representation(self, value):
968981
"""
@@ -1058,7 +1071,7 @@ def to_internal_value(self, data):
10581071
return parsed.time()
10591072

10601073
# Throw exception.
1061-
self.fail('invalid', format=data)
1074+
self.fail_field_validation('invalid', format=data)
10621075

10631076
def to_representation(self, value):
10641077
"""
@@ -1145,7 +1158,7 @@ def to_internal_value(self, data):
11451158
# Check ot the data ot datetime object.
11461159
if isinstance(data, datetime.date):
11471160
if not isinstance(data, datetime.datetime):
1148-
self.fail('date')
1161+
self.fail_field_validation('date')
11491162
else:
11501163
return data
11511164

@@ -1156,7 +1169,7 @@ def to_internal_value(self, data):
11561169
pass
11571170

11581171
# Throw error.
1159-
self.fail('invalid', format=data)
1172+
self.fail_field_validation('invalid', format=data)
11601173

11611174
def to_representation(self, value):
11621175
"""
@@ -1207,7 +1220,7 @@ def to_internal_value(self, data):
12071220
try:
12081221
return json.loads(data, encoding='utf8')
12091222
except (JSONDecodeError, TypeError, ValueError):
1210-
self.fail('invalid')
1223+
self.fail_field_validation('invalid')
12111224

12121225
def to_representation(self, value):
12131226
"""
@@ -1222,7 +1235,7 @@ def to_representation(self, value):
12221235
try:
12231236
return json.dumps(value)
12241237
except (TypeError, ValueError):
1225-
self.fail('invalid')
1238+
self.fail_field_validation('invalid')
12261239

12271240

12281241
class DictField(JsonField):
@@ -1275,7 +1288,7 @@ def to_internal_value(self, data):
12751288
data = html.parse_html_dict(data)
12761289

12771290
if not isinstance(data, dict):
1278-
self.fail('not_a_dict', input_type=type(data).__name__)
1291+
self.fail_field_validation('not_a_dict', input_type=type(data).__name__)
12791292

12801293
return {
12811294
six.text_type(key): self.child.run_validation(value)

tests/test_fields.py

+39-8
Original file line numberDiff line numberDiff line change
@@ -251,34 +251,65 @@ def test_bind(self):
251251
field.bind('test_label', self)
252252
self.assert_bind(field, 'test_label', self, 'test_label')
253253

254-
def test_fail(self):
254+
def test_fail_field_validation(self):
255255
"""
256-
Testing fail method.
256+
Testing fail_field_validation method.
257257
258258
"""
259259
# We test without our errors.
260260
field = self.field_class(**self.create_params())
261261
try:
262-
field.fail('required')
263-
self.fail('`.fail()` must throw as exception `ValidationError`.')
262+
field.fail_field_validation('required')
263+
self.fail('`.fail_field_validation()` must throw as exception `ValidationError`.')
264264
except ValidationError:
265265
pass
266266
try:
267-
field.fail('test')
268-
self.fail('`.fail()` must throw as exception `AssertionError`.')
267+
field.fail_field_validation('test')
268+
self.fail('`.fail_field_validation()` must throw as exception `AssertionError`.')
269269
except AssertionError:
270270
pass
271271

272272
# Now add custom error message
273273
field = self.field_class(**self.create_params(error_messages={'test': '{test}-test'}))
274274
try:
275-
field.fail('test', test='test')
276-
self.fail('`.fail()` must throw as exception `ValidationError`.')
275+
field.fail_field_validation('test', test='test')
276+
self.fail('`.fail_field_validation()` must throw as exception `ValidationError`.')
277277
except ValidationError as e:
278278
assert e.detail == 'test-test', 'The error message should be `{}`, reality `{}`.'.format(
279279
'test-test', e.detail
280280
)
281281

282+
def test_fail(self):
283+
"""
284+
Testing fail method.
285+
286+
"""
287+
field = self.field_class(**self.create_params())
288+
detail = {'error': 'test'}
289+
try:
290+
field.fail(detail=detail)
291+
self.fail('`.fail()` must throw as exception `ValidationError`.')
292+
except ValidationError as e:
293+
self.assertEqual(
294+
e.detail, detail,
295+
'ValidationError.detail not equal source error. '
296+
'Should be: `{}`, reality: `{}`.'.format(detail, e.detail)
297+
)
298+
self.assertEqual(
299+
e.status, 400,
300+
'ValidationError.status = `{}`. This is not 400.'.format(e.status)
301+
)
302+
status = 404
303+
try:
304+
field.fail(detail=detail, status=status)
305+
self.fail('`.fail()` must throw as exception `ValidationError`.')
306+
except ValidationError as e:
307+
self.assertEqual(
308+
e.status, status,
309+
'ValidationError.status not equal source status. '
310+
'Should be: `{}`, reality: `{}`.'.format(status, e.status)
311+
)
312+
282313
def test_abstract_methods(self):
283314
"""
284315
Testing abstract methods.

0 commit comments

Comments
 (0)