Skip to content

Commit 30f7d29

Browse files
committed
#93 v4.4.0, InvalidRequestError.to_dict() added
1 parent 4ef4e29 commit 30f7d29

File tree

4 files changed

+77
-107
lines changed

4 files changed

+77
-107
lines changed

flask_request_validator/error_formatter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
def demo_error_formatter(error: Union[InvalidRequestError, InvalidHeadersError, AfterParamError]) -> list:
66
"""
77
Just demo. !!! not supported !!!
8+
@deprecated v5.0
89
"""
910
if isinstance(error, (InvalidHeadersError, AfterParamError)):
1011
return [str(error)]

flask_request_validator/exceptions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,25 @@ def __init__(
232232
self.get = get
233233
self.form = form
234234
self.files = files
235+
236+
def to_dict(self) -> dict:
237+
result = dict()
238+
for error_type in ('json', 'files'):
239+
errors = getattr(self, error_type)
240+
if not (isinstance(errors, list) and len(errors) > 0):
241+
continue
242+
243+
result.setdefault(error_type, [])
244+
for error in errors:
245+
result[error_type].append(error)
246+
247+
for error_type in ('get', 'form', 'path', 'json'):
248+
errors = getattr(self, error_type)
249+
if not (isinstance(errors, dict) and len(errors) > 0):
250+
continue
251+
252+
result.setdefault(error_type, dict())
253+
for key, error in errors.items():
254+
result[error_type][key] = error
255+
256+
return result

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
setup(
1212
name='flask_request_validator',
13-
version='4.3.1',
13+
version='4.4.0',
1414
description='Flask request data validation',
1515
long_description=DESCRIPTION,
1616
url='https://github.com/d-ganchar/flask_request_validator',

tests/test_validator.py

Lines changed: 53 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from flask_restful import Api
77
from parameterized import parameterized
88

9-
from flask_request_validator.error_formatter import demo_error_formatter
109
from flask_request_validator.rules import *
1110
from flask_request_validator.validator import *
1211

@@ -348,8 +347,12 @@ def test_default_value(self):
348347

349348

350349
@_app2.errorhandler(RequestError)
351-
def handler(e):
352-
return flask.jsonify(demo_error_formatter(e)), 400
350+
def handler(e: InvalidRequestError):
351+
if isinstance(e, InvalidRequestError):
352+
return str(e.to_dict()), 400
353+
if isinstance(e, AfterParamError):
354+
return str(e), 400
355+
raise e
353356

354357

355358
@_app2.route('/', methods=['POST'])
@@ -414,28 +417,16 @@ class TestNestedJson(TestCase):
414417
],
415418
}
416419
},
417-
[
418-
{
419-
'errors': [
420-
{'keys': {'description': 'invalid length, min length = 5',
421-
'status': 'not allowed, allowed values: active|not_active'},
422-
'path': 'root|music|bands|details'},
423-
{'list_items': {'0': {'name': 'invalid length, min length = 3'},
424-
'1': {'name': 'invalid length, min length = 3'}},
425-
'path': 'root|music|bands|persons'}, {
426-
'keys': {'description': 'invalid length, min length = 5',
427-
'status': 'not allowed, allowed values: active|not_active'},
428-
'path': 'root|music|bands|details'},
429-
{'list_items': {'0': {'name': 'invalid length, min length = 3'}},
430-
'path': 'root|music|bands|persons'},
431-
{'list_items': {'0': {'name': 'invalid length, min length = 2'},
432-
'1': {'name': 'invalid length, min length = 2'}},
433-
'path': 'root|music|bands'}, {
434-
'keys': {'island': 'value does not match pattern ^[a-z]{4,20}$',
435-
'iso': 'expected a datetime in ISO format'}, 'path': 'root'}],
436-
'message': 'invalid JSON parameters'
437-
}
438-
],
420+
b"{'json': [JsonError(['root', 'music', 'bands', 'details'], {'description': "
421+
b"RulesError(ValueMinLengthError(5)), 'status': RulesError(ValueEnumError(('active', 'not_active')))}, "
422+
b"False), JsonError(['root', 'music', 'bands', 'persons'], {0: "
423+
b"{'name': RulesError(ValueMinLengthError(3))}, 1: {'name': RulesError(ValueMinLengthError(3))}}, True), "
424+
b"JsonError(['root', 'music', 'bands', 'details'], {'description': RulesError(ValueMinLengthError(5)), "
425+
b"'status': RulesError(ValueEnumError(('active', 'not_active')))}, False), "
426+
b"JsonError(['root', 'music', 'bands', 'persons'], {0: {'name': RulesError(ValueMinLengthError(3))}}, "
427+
b"True), JsonError(['root', 'music', 'bands'], {0: {'name': RulesError(ValueMinLengthError(2))}, 1: "
428+
b"{'name': RulesError(ValueMinLengthError(2))}}, True), JsonError(['root'], {'island': "
429+
b"RulesError(ValuePatternError('^[a-z]{4,20}$')), 'iso': RulesError(ValueDtIsoFormatError())}, False)]}",
439430
'400 BAD REQUEST',
440431
),
441432
# valid
@@ -477,91 +468,40 @@ class TestNestedJson(TestCase):
477468
],
478469
}
479470
},
480-
{
481-
'json': {
482-
'island': 'valid', 'iso': '2021-01-02', 'music': {
483-
'bands': [
484-
{
485-
'name': 'Metallica',
486-
'details': {
487-
'details': 'Los Angeles, California, U.S.',
488-
'description': 'very long description',
489-
'status': 'active',
490-
},
491-
'persons': [
492-
{'name': 'James Hetfield'},
493-
{'name': 'Lars Ulrich'},
494-
{'name': 'Kirk Hammett'},
495-
{'name': 'Robert Trujillo'},
496-
]
497-
},
498-
{
499-
'name': 'AC/DC',
500-
'details': {
501-
'details': 'Sydney, Australia',
502-
'status': 'active',
503-
'description': 'positive',
504-
},
505-
'persons': [
506-
{'name': 'Angus Young'},
507-
{'name': 'Stevie Young'},
508-
{'name': 'Brian Johnson'},
509-
{'name': 'Phil Rudd'},
510-
{'name': 'Cliff Williams'},
511-
],
512-
},
513-
]
514-
}
515-
}
516-
},
471+
b'{"json":{"island":"valid","iso":"2021-01-02","music":{"bands":[{"details":{"description":"very '
472+
b'long description","details":"Los Angeles, California, U.S.","status":"active"},"name":"Metallica",'
473+
b'"persons":[{"name":"James Hetfield"},{"name":"Lars Ulrich"},{"name":"Kirk Hammett"},'
474+
b'{"name":"Robert Trujillo"}]},{"details":{"description":"positive","details":"Sydney, '
475+
b'Australia","status":"active"},"name":"AC/DC","persons":[{"name":"Angus Young"},{"name":"Stevie Young"},'
476+
b'{"name":"Brian Johnson"},{"name":"Phil Rudd"},{"name":"Cliff Williams"}]}]}}}\n',
517477
'200 OK'
518478
),
519479
])
520480
def test_json_route_with_error_formatter(self, data, expected, status):
521481
with _app2.test_client() as client:
522482
response = client.post('/', data=json.dumps(data), content_type='application/json')
523483
self.assertEqual(response.status, status)
524-
self.assertEqual(response.json, expected)
484+
self.assertEqual(response.data, expected)
525485

526486
@parameterized.expand([
527487
(
528488
[{'key': 'testKey', 'value': 'testValue'}],
529-
[{
530-
'errors': [{'list_items': {'0': {'namespace': 'key is required'}}, 'path': 'root'}],
531-
'message': 'invalid JSON parameters',
532-
}],
489+
b"{'json': [JsonError(['root'], {0: {'namespace': RulesError(MissingJsonKeyError('namespace'))}}, True)]}"
533490
),
534491
(
535492
[{}, {'unknown_field': 'value'}],
536-
[
537-
{
538-
'errors': [
539-
{
540-
'list_items': {
541-
'0': {
542-
'key': 'key is required',
543-
'namespace': 'key is required',
544-
'value': 'key is required',
545-
},
546-
'1': {
547-
'key': 'key is required',
548-
'namespace': 'key is required',
549-
'value': 'key is required',
550-
},
551-
},
552-
'path': 'root',
553-
},
554-
],
555-
'message': 'invalid JSON parameters',
556-
},
557-
],
493+
b"{'json': [JsonError(['root'], {0: {'namespace': RulesError(MissingJsonKeyError('namespace')), "
494+
b"'key': RulesError(MissingJsonKeyError('key')), 'value': RulesError(MissingJsonKeyError('value'))}, "
495+
b"1: {'namespace': RulesError(MissingJsonKeyError('namespace')), "
496+
b"'key': RulesError(MissingJsonKeyError('key')), "
497+
b"'value': RulesError(MissingJsonKeyError('value'))}}, True)]}"
558498
)
559499
])
560500
def test_issue_82_negative(self, data, expected):
561501
with _app2.test_client() as client:
562502
response = client.post('/issue/82', data=json.dumps(data), content_type='application/json')
563503
self.assertEqual(response.status, '400 BAD REQUEST')
564-
self.assertEqual(response.json, expected)
504+
self.assertEqual(response.data, expected)
565505

566506
def test_issue_82_positive(self):
567507
with _app2.test_client() as client:
@@ -616,20 +556,16 @@ class TestAfterParam(TestCase):
616556
@parameterized.expand([
617557
(
618558
['2021-01-01', '2021-01-'],
619-
[{'errors': [
620-
{'list_items': {'1': 'expected a datetime in %Y-%m-%d format'},
621-
'path': 'root|dates'}], 'message': 'invalid JSON parameters'}]
559+
b"{'json': [JsonError(['root', 'dates'], {1: RulesError(ValueDatetimeError('%Y-%m-%d'))}, True)]}",
622560
),
623561
(
624562
['2021'],
625-
[{'errors': [{'list_items': {'0': 'expected a datetime in %Y-%m-%d format'},
626-
'path': 'root|dates'}],
627-
'message': 'invalid JSON parameters'}]
563+
b"{'json': [JsonError(['root', 'dates'], {0: RulesError(ValueDatetimeError('%Y-%m-%d'))}, True)]}",
628564
),
629565
# valid
630566
(
631567
['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04'],
632-
['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04'],
568+
b'["2021-01-01","2021-01-02","2021-01-03","2021-01-04"]\n',
633569
),
634570
])
635571
def test_after_param_rules(self, dates, expected):
@@ -638,28 +574,39 @@ def test_after_param_rules(self, dates, expected):
638574
'/after_param',
639575
data=json.dumps({'dates': dates}),
640576
content_type='application/json',
641-
).json
577+
)
642578

643-
self.assertEqual(result, expected)
579+
self.assertEqual(result.data, expected)
644580

645581
@parameterized.expand([
646582
# valid
647583
(
648584
['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04'],
649-
['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04'],
585+
'200 OK',
586+
b'["2021-01-01","2021-01-02","2021-01-03","2021-01-04"]\n',
650587
),
651588
# invalid
652-
(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-01'], ['2021-01-01 < 2021-01-03']),
653-
(['2021-01-10', '2021-01-01', ], ['2021-01-01 < 2021-01-10']),
589+
(
590+
['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-01'],
591+
'400 BAD REQUEST',
592+
b'2021-01-01 < 2021-01-03',
593+
),
594+
(
595+
['2021-01-10', '2021-01-01'],
596+
'400 BAD REQUEST',
597+
b'2021-01-01 < 2021-01-10',
598+
),
654599
])
655-
def test_after_params(self, dates, expected):
600+
def test_after_params(self, dates, expected_status, expected):
656601
with _app2.test_client() as client:
657-
data = client.post(
602+
response = client.post(
658603
'/after_param',
659604
data=json.dumps({'dates': dates}),
660605
content_type='application/json',
661-
).json
662-
self.assertEqual(data, expected)
606+
)
607+
608+
self.assertEqual(response.status, expected_status)
609+
self.assertEqual(response.data, expected)
663610

664611

665612
@_app2.route('/issue/83', methods=['POST'])

0 commit comments

Comments
 (0)