Skip to content

Commit

Permalink
feat: Add some changes to ValidationError to support django style vad…
Browse files Browse the repository at this point in the history
…ation errors (encode#8863)
  • Loading branch information
Ehsan200 committed Feb 6, 2023
1 parent 22d206c commit 4abfa28
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 3 deletions.
19 changes: 16 additions & 3 deletions rest_framework/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,30 @@ class ValidationError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _('Invalid input.')
default_code = 'invalid'
default_params = {}

def __init__(self, detail=None, code=None):
def __init__(self, detail=None, code=None, params=None):
if detail is None:
detail = self.default_detail
if code is None:
code = self.default_code
if params is None:
params = self.default_params

# For validation failures, we may collect many errors together,
# so the details should always be coerced to a list if not already.
if isinstance(detail, tuple):
detail = list(detail)
if isinstance(detail, str):
detail = [detail % params]
elif isinstance(detail, ValidationError):
detail = detail.detail
elif isinstance(detail, (list, tuple)):
final_detail = []
for detail_item in detail:
if isinstance(detail_item, ValidationError):
final_detail += detail_item.detail
else:
final_detail += [detail_item % params if isinstance(detail_item, str) else detail_item]
detail = final_detail
elif not isinstance(detail, dict) and not isinstance(detail, list):
detail = [detail]

Expand Down
86 changes: 86 additions & 0 deletions tests/test_validation_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,89 @@ def test_validation_error_details(self):
assert len(error.detail) == 2
assert str(error.detail[0]) == 'message1'
assert str(error.detail[1]) == 'message2'


class TestValidationErrorWithDjangoStyle(TestCase):
def test_validation_error_details(self):
error = ValidationError('Invalid value: %(value)s', params={'value': '42'})
assert str(error.detail[0]) == 'Invalid value: 42'

def test_validation_error_details_tuple(self):
error = ValidationError(
detail=('Invalid value: %(value1)s', 'Invalid value: %(value2)s'),
params={'value1': '42', 'value2': '43'},
)
assert isinstance(error.detail, list)
assert len(error.detail) == 2
assert str(error.detail[0]) == 'Invalid value: 42'
assert str(error.detail[1]) == 'Invalid value: 43'

def test_validation_error_details_list(self):
error = ValidationError(
detail=['Invalid value: %(value1)s', 'Invalid value: %(value2)s', ],
params={'value1': '42', 'value2': '43'}
)
assert isinstance(error.detail, list)
assert len(error.detail) == 2
assert str(error.detail[0]) == 'Invalid value: 42'
assert str(error.detail[1]) == 'Invalid value: 43'

def test_validation_error_details_validation_errors(self):
error = ValidationError(
detail=ValidationError(
detail='Invalid value: %(value1)s',
params={'value1': '42'},
),
)
assert isinstance(error.detail, list)
assert len(error.detail) == 1
assert str(error.detail[0]) == 'Invalid value: 42'

def test_validation_error_details_validation_errors_list(self):
error = ValidationError(
detail=[
ValidationError(
detail='Invalid value: %(value1)s',
params={'value1': '42'},
),
ValidationError(
detail='Invalid value: %(value2)s',
params={'value2': '43'},
),
'Invalid value: %(value3)s'
],
params={'value3': '44'}
)
assert isinstance(error.detail, list)
assert len(error.detail) == 3
assert str(error.detail[0]) == 'Invalid value: 42'
assert str(error.detail[1]) == 'Invalid value: 43'
assert str(error.detail[2]) == 'Invalid value: 44'

def test_validation_error_details_validation_errors_nested_list(self):
error = ValidationError(
detail=[
ValidationError(
detail='Invalid value: %(value1)s',
params={'value1': '42'},
),
ValidationError(
detail=[
'Invalid value: %(value2)s',
ValidationError(
detail='Invalid value: %(value3)s',
params={'value3': '44'},
)
],
params={'value2': '43'},
),
'Invalid value: %(value4)s'
],
params={'value4': '45'}
)
assert isinstance(error.detail, list)
assert len(error.detail) == 4
assert str(error.detail[0]) == 'Invalid value: 42'
assert str(error.detail[1]) == 'Invalid value: 43'
assert str(error.detail[2]) == 'Invalid value: 44'
assert str(error.detail[3]) == 'Invalid value: 45'

0 comments on commit 4abfa28

Please sign in to comment.