├── =2.0.1 ├── LIVR ├── __init__.py ├── Rules │ ├── __init__.py │ ├── constants.py │ ├── Common.py │ ├── Modifiers.py │ ├── Special.py │ ├── Numeric.py │ ├── String.py │ └── Meta.py ├── test │ ├── __init__.py │ ├── test_suite │ │ ├── __init__.py │ │ ├── aliases_negative │ │ │ ├── __init__.py │ │ │ ├── 01-adult_age │ │ │ │ ├── __init__.py │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ ├── aliases.json │ │ │ │ └── rules.json │ │ │ ├── 02-address │ │ │ │ ├── rules.json │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── aliases.json │ │ │ └── 03-adult_age_in_user │ │ │ │ ├── rules.json │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── aliases.json │ │ ├── negative │ │ │ ├── 02-not_empty │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 01-required │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 19-list_of │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 22-not_empty_list │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 05-max_length │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 08-like │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 17-equal_to_field │ │ │ │ ├── 23-url │ │ │ │ │ ├── errors.json │ │ │ │ │ ├── rules.json │ │ │ │ │ └── input.json │ │ │ │ ├── 24-iso_date │ │ │ │ │ ├── errors.json │ │ │ │ │ ├── rules.json │ │ │ │ │ └── input.json │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 04-min_length │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 06-length_equal │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 07-lenght_between │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 24-iso_date │ │ │ │ ├── errors.json │ │ │ │ ├── rules.json │ │ │ │ └── input.json │ │ │ ├── 26-string │ │ │ │ ├── input.json │ │ │ │ ├── rules.json │ │ │ │ └── errors.json │ │ │ ├── 27-any_object │ │ │ │ ├── input.json │ │ │ │ ├── rules.json │ │ │ │ └── errors.json │ │ │ ├── 18-nested_object │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 20-list_of_objects │ │ │ │ ├── rules.json │ │ │ │ ├── errors.json │ │ │ │ └── input.json │ │ │ ├── 23-url │ │ │ │ ├── errors.json │ │ │ │ ├── rules.json │ │ │ │ └── input.json │ │ │ ├── 13-max_number │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 14-min_number │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 25-eq │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 03-one_of │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 15-number_beetween │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 29-or │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 09-integer │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 11-decimal │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 10-positive_integer │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 16-email │ │ │ │ ├── rules.json │ │ │ │ ├── errors.json │ │ │ │ └── input.json │ │ │ ├── 12-positive_decimal │ │ │ │ ├── input.json │ │ │ │ ├── errors.json │ │ │ │ └── rules.json │ │ │ ├── 28-variable_object │ │ │ │ ├── errors.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ └── 21-list_of_different_objects │ │ │ │ ├── errors.json │ │ │ │ ├── rules.json │ │ │ │ └── input.json │ │ ├── positive │ │ │ ├── 19-list_of │ │ │ │ ├── input.json │ │ │ │ ├── output.json │ │ │ │ └── rules.json │ │ │ ├── 02-not_empty │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 09-integer │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 13-max_number │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 14-min_number │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 15-number_between │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 10-positive_integer │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 01-required │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 23-url │ │ │ │ ├── rules.json │ │ │ │ ├── output.json │ │ │ │ └── input.json │ │ │ ├── 26-string │ │ │ │ ├── output.json │ │ │ │ ├── rules.json │ │ │ │ └── input.json │ │ │ ├── 11-decimal │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 16-email │ │ │ │ ├── rules.json │ │ │ │ ├── output.json │ │ │ │ └── input.json │ │ │ ├── 17-equal_to_field │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 22-not_empty_list │ │ │ │ ├── output.json │ │ │ │ ├── rules.json │ │ │ │ └── input.json │ │ │ ├── 08-like │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 12-positive_decimal │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 25-eq │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 34-leave_only │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 30-trim │ │ │ │ ├── rules.json │ │ │ │ ├── output.json │ │ │ │ └── input.json │ │ │ ├── 32-to_uc │ │ │ │ ├── rules.json │ │ │ │ ├── input.json │ │ │ │ └── output.json │ │ │ ├── 04-min_length │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 05-max_length │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 18-nested_object │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 06-length_equal │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 07-length_between │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 27-any_object │ │ │ │ ├── input.json │ │ │ │ ├── output.json │ │ │ │ └── rules.json │ │ │ ├── 33-remove │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 24-iso_date │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 03-one_of │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 31-to_lc │ │ │ │ ├── input.json │ │ │ │ ├── output.json │ │ │ │ └── rules.json │ │ │ ├── 20-list_of_objects │ │ │ │ ├── rules.json │ │ │ │ ├── output.json │ │ │ │ └── input.json │ │ │ ├── 28-variable_object │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ ├── 29-or │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ │ └── 21-list_of_different_objects │ │ │ │ ├── output.json │ │ │ │ ├── input.json │ │ │ │ └── rules.json │ │ └── aliases_positive │ │ │ ├── 02-address │ │ │ ├── rules.json │ │ │ ├── output.json │ │ │ ├── input.json │ │ │ └── aliases.json │ │ │ ├── 03-adult_age_in_user │ │ │ ├── rules.json │ │ │ ├── output.json │ │ │ ├── input.json │ │ │ └── aliases.json │ │ │ └── 01-adult_age │ │ │ ├── output.json │ │ │ ├── input.json │ │ │ ├── aliases.json │ │ │ └── rules.json │ ├── livr_test.py │ ├── test_suite.py │ └── case_handler.py ├── Validator.py ├── BuildAliasedRule.py ├── DEFAULT_RULES.py └── internal_reactor.py ├── .gitignore ├── LIVR.egg-info ├── top_level.txt ├── dependency_links.txt ├── SOURCES.txt └── PKG-INFO ├── dist ├── LIVR-2.0.tar.gz ├── LIVR-2.0.1.tar.gz ├── LIVR-2.0-py2-none-any.whl ├── LIVR-2.0.1-py2-none-any.whl └── LIVR-2.0.1-py2.py3-none-any.whl ├── .travis.yml ├── MANIFEST ├── setup.py └── README.rst /=2.0.1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | -------------------------------------------------------------------------------- /LIVR/Rules/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR/test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | LIVR 2 | -------------------------------------------------------------------------------- /LIVR.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/01-adult_age/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/02-not_empty/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "CANNOT_BE_EMPTY" 3 | } -------------------------------------------------------------------------------- /dist/LIVR-2.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asholok/python-validator-livr/HEAD/dist/LIVR-2.0.tar.gz -------------------------------------------------------------------------------- /dist/LIVR-2.0.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asholok/python-validator-livr/HEAD/dist/LIVR-2.0.1.tar.gz -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/19-list_of/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": [ 10, 20, 100, 10 ], 3 | "user_ids": "" 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/19-list_of/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": [ 10, 20, 100, 10 ], 3 | "user_ids": "" 4 | } -------------------------------------------------------------------------------- /dist/LIVR-2.0-py2-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asholok/python-validator-livr/HEAD/dist/LIVR-2.0-py2-none-any.whl -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/01-required/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "", 3 | "last_name": null, 4 | "age": "25" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/02-not_empty/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "", 3 | "last_name": null, 4 | "age": "25" 5 | } -------------------------------------------------------------------------------- /dist/LIVR-2.0.1-py2-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asholok/python-validator-livr/HEAD/dist/LIVR-2.0.1-py2-none-any.whl -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/19-list_of/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": [ -10, "", 50, 120 ], 3 | "user_ids": "not an array" 4 | } -------------------------------------------------------------------------------- /dist/LIVR-2.0.1-py2.py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asholok/python-validator-livr/HEAD/dist/LIVR-2.0.1-py2.py3-none-any.whl -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/02-not_empty/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "N/A", 4 | "salary": 0 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/09-integer/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 0, 4 | "number3": -1, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/02-address/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "address", 3 | "address_custom_error": "address_with_custom_error" 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/03-adult_age_in_user/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "user", 3 | "user_custom_error": ["user_with_custom_error"] 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/02-address/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "address", 3 | "address_custom_error": "address_with_custom_error" 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/03-adult_age_in_user/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": "user", 3 | "user_custom_error": ["user_with_custom_error"] 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/22-not_empty_list/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "list1": [], 3 | "list2": [], 4 | "not_list": {}, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/13-max_number/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 15, 4 | "number3": -10, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/14-min_number/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 25, 4 | "number3": 40, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/01-required/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "REQUIRED", 3 | "last_name": "REQUIRED", 4 | "middle_name": "REQUIRED" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/05-max_length/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "TOO_LONG", 3 | "last_name": "TOO_LONG", 4 | "middle_name": "TOO_LONG" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/08-like/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "WRONG_FORMAT", 3 | "last_name": "WRONG_FORMAT", 4 | "age": "WRONG_FORMAT" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/23-url/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "WRONG_URL", 3 | "url2": "WRONG_URL", 4 | "url3": "WRONG_URL" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/02-not_empty/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "N/A", 4 | "age": "25", 5 | "salary": 0 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/15-number_between/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 25.55, 4 | "number3": 0, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/04-min_length/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "TOO_SHORT", 3 | "last_name": "TOO_SHORT", 4 | "middle_name": "TOO_SHORT" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/06-length_equal/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "TOO_LONG", 3 | "last_name": "TOO_SHORT", 4 | "middle_name": "TOO_LONG" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/07-lenght_between/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "TOO_SHORT", 3 | "last_name": "TOO_LONG", 4 | "middle_name": "TOO_LONG" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/24-iso_date/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "WRONG_DATE", 3 | "iso_date2": "WRONG_DATE", 4 | "iso_date3": "WRONG_DATE" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/10-positive_integer/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 999999, 4 | "number3": 1, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/01-required/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some", 5 | "salary": 0 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/23-url/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "url", 3 | "url2": { "url": [] }, 4 | "url3": [ { "url": [] } ], 5 | "empty_field": "url" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/01-required/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "required", 3 | "last_name": ["required"], 4 | "middle_name": [ { "required": [] } ] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/02-not_empty/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "not_empty", 3 | "last_name": ["not_empty"], 4 | "middle_name": [ { "not_empty": [] } ] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/19-list_of/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": [ "NOT_POSITIVE_INTEGER", "REQUIRED", null, "TOO_HIGH" ], 3 | "user_ids": "FORMAT_ERROR" 4 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/24-iso_date/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "WRONG_DATE", 3 | "iso_date2": "WRONG_DATE", 4 | "iso_date3": "WRONG_DATE" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": "FIELDS_NOT_EQUAL", 3 | "field2": "FIELDS_NOT_EQUAL", 4 | "field3": "FIELDS_NOT_EQUAL" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/26-string/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "number1": "2", 5 | "number2": "2", 6 | "empty_city": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/09-integer/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": 0, 4 | "number3": -1, 5 | "empty_field": "", 6 | "extra_field": "100" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/11-decimal/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10.12, 3 | "number2": 0.55, 4 | "number3": -1.10, 5 | "number4": -3.00, 6 | "empty_field": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/14-min_number/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": 25, 4 | "number3": 40, 5 | "empty_field": "", 6 | "extra_field": "100" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/16-email/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "email", 3 | "email2": { "email": [] }, 4 | "email3": [ { "email": [] } ], 5 | "empty_field": "email" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/23-url/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "url", 3 | "url2": { "url": [] }, 4 | "url3": [ { "url": [] } ], 5 | "empty_field": "url" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/01-required/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some", 5 | "age": "25", 6 | "salary": 0 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/13-max_number/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": 15, 4 | "number3": -10, 5 | "empty_field": "", 6 | "extra_field": "100" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/17-equal_to_field/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": "some value", 3 | "field2": "some value", 4 | "field3": "some value", 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/22-not_empty_list/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "list_with_numbers": [0], 3 | "list_with_objects": [{},{"key": "123"}], 4 | "list_with_arrays": [[1,2,3]] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/10-positive_integer/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": 999999, 4 | "number3": 1, 5 | "empty_field": "", 6 | "extra_field": "100" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/15-number_between/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": "25.55", 4 | "number3": "0", 5 | "empty_field": "", 6 | "extra_field": "100" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/08-like/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "age": "35", 5 | "empty_name": "", 6 | "extra_name": "extra_name" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/08-like/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Ivanovich", 5 | "age": "35", 6 | "empty_name": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/12-positive_decimal/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": 10, 3 | "number2": 120.11, 4 | "number3": 99999.9999, 5 | "number4": 0.01, 6 | "empty_field": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/25-eq/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "city3": "Kiev", 5 | "number1": 2, 6 | "number2": "2", 7 | "empty_city": "" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/34-leave_only/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "Vl l Vl", 3 | "object": {"string_value": "a-vaa"}, 4 | "list_of_string_values": ["", {"key": "123"}, "23"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/30-trim/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "trim", 3 | "object": {"nested_object": {"string_value": "trim"} }, 4 | "list_of_string_values": {"list_of": "trim"} 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/32-to_uc/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "to_uc", 3 | "object": {"nested_object": {"string_value": "to_uc"} }, 4 | "list_of_string_values": {"list_of": "to_uc"} 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/24-iso_date/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "iso_date", 3 | "iso_date2": { "iso_date": [] }, 4 | "iso_date3": [ { "iso_date": [] } ], 5 | "empty_field": "iso_date" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/01-required/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "required", 3 | "last_name": ["required"], 4 | "middle_name": [ { "required": [] } ], 5 | "salary": { "required": [] } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/04-min_length/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": "1111", 6 | "empty_name": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/05-max_length/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Васек", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": "1111", 6 | "empty_name": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/16-email/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "test@mail.com", 3 | "email2": "test.test@mail.com.ua", 4 | "email3": "test+test.t_e_s_t@mail.in.ua", 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/18-nested_object/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "country": "Ukraine", 4 | "zip": 12345, 5 | "street": "10", 6 | "building": 10 7 | } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/26-string/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "string", 3 | "city2": [{ "string": [] }], 4 | "number1": "string", 5 | "number2": "string", 6 | "empty_city": "string" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/30-trim/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "value", 3 | "object": {"string_value": "some value"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value2"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/32-to_uc/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "Value", 3 | "object": {"string_value": "Some Value"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value2"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/32-to_uc/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "VALUE", 3 | "object": {"string_value": "SOME VALUE"}, 4 | "list_of_string_values": ["VALUE1", {"key": "123"}, "VALUE2"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/26-string/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_hash": {"test": 1}, 3 | "value_is_empty_hash": {}, 4 | "value_is_array": ["test", 1], 5 | "value_is_empty_array": [] 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/27-any_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_string": "test", 3 | "value_is_number": 0, 4 | "value_is_array": ["test", 1], 5 | "value_is_empty_array": [] 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/02-not_empty/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "not_empty", 3 | "last_name": ["not_empty"], 4 | "middle_name": [ { "not_empty": [] } ], 5 | "salary": { "required": [] } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/06-length_equal/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": "1111", 6 | "empty_name": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/07-length_between/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": "1111", 6 | "empty_name": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/22-not_empty_list/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "list_with_numbers": "not_empty_list", 3 | "list_with_objects": [{ "not_empty_list" : [] }], 4 | "list_with_arrays": "not_empty_list" 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/26-string/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "number1": "2", 5 | "number2": 2, 6 | "empty_city": "", 7 | "extra_city": "New York" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/30-trim/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": " value ", 3 | "object": {"string_value": " some value "}, 4 | "list_of_string_values": [" value1 ", {"key": "123"}, " value2 "] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/01-adult_age/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "age3": "TOO_LOW", 3 | "age4": "NOT_POSITIVE_INTEGER", 4 | "age3_custom_error": "WRONG_AGE", 5 | "age4_custom_error": "WRONG_AGE" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/04-min_length/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "empty_name": "", 6 | "extra_name": "extra_name" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/05-max_length/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "empty_name": "", 6 | "extra_name": "extra_name" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/06-length_equal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "empty_name": "", 6 | "extra_name": "extra_name" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/11-decimal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10.12", 3 | "number2": 0.55, 4 | "number3": -1.10, 5 | "number4": -3.00, 6 | "empty_field": "", 7 | "extra_field": "100" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/22-not_empty_list/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "list_with_numbers": [0], 3 | "list_with_objects": [{},{"key": "123"}], 4 | "list_with_arrays": [[1,2,3]], 5 | "extra_field": [1,2,3] 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/27-any_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "object1": {"email": "user@mail.com"}, 3 | "object2": {"id": 123, "address": {"city" : "Kiev"}}, 4 | "object3": {}, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/27-any_object/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "object1": {"email": "user@mail.com"}, 3 | "object2": {"id": 123, "address": {"city" : "Kiev"}}, 4 | "object3": {}, 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/33-remove/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "aluevaluealue", 3 | "object": {"string_value": "Vluelue Vlue"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/07-lenght_between/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "empty_name": "", 6 | "extra_name": "extra_name" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": "some value1", 3 | "field2": "some value", 4 | "field3": "some value", 5 | "empty_field": "", 6 | "extra_field": "some value" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/24-iso_date/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "2014-13-10", 3 | "iso_date2": "2011-02-29", 4 | "iso_date3": "2014-10-10T22:22", 5 | "empty_field": "", 6 | "extra_field": "aaaa" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/26-string/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_hash": "string", 3 | "value_is_empty_hash": "string", 4 | "value_is_array": "string", 5 | "value_is_empty_array": "string" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/11-decimal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "decimal", 3 | "number2": ["decimal"], 4 | "number3": [ { "decimal": [] } ], 5 | "number4": "decimal", 6 | "empty_field": "decimal" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/17-equal_to_field/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": "some value", 3 | "field2": "some value", 4 | "field3": "some value", 5 | "empty_field": "", 6 | "extra_field": "some value" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/24-iso_date/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "2014-02-18", 3 | "iso_date2": "1930-03-30", 4 | "iso_date3": "1930-01-01", 5 | "iso_date4": "1970-01-01", 6 | "empty_field": "" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/24-iso_date/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "iso_date", 3 | "iso_date2": { "iso_date": [] }, 4 | "iso_date3": [ { "iso_date": [] } ], 5 | "empty_field": "iso_date" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/03-one_of/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "city3": "Kiev", 5 | "number1": 2, 6 | "number2": "2", 7 | "boolean": true, 8 | "empty_city": "" 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/08-like/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Ivanovich", 5 | "age": 35, 6 | "empty_name": "", 7 | "extra_name": "extra_name" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/09-integer/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "integer", 3 | "number2": ["integer"], 4 | "number3": [ { "integer": [] } ], 5 | "empty_field": "integer", 6 | "missed_field": "integer" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/33-remove/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "Value value Value", 3 | "object": {"string_value": "Value-value |Value|"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value2"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/13-max_number/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "max_number": 10 }, 3 | "number2": { "max_number": [20] }, 4 | "number3": [ { "max_number": [30] } ], 5 | "empty_field": { "max_number": 10 } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/14-min_number/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "min_number": 10 }, 3 | "number2": { "min_number": [20] }, 4 | "number3": [ { "min_number": [30] } ], 5 | "empty_field": { "min_number": 10 } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/25-eq/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "city3": "Kiev", 5 | "number1": "2", 6 | "number2": 2, 7 | "empty_city": "", 8 | "extra_city": "New York" 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/34-leave_only/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "Value value Value", 3 | "object": {"string_value": "Value-value |Value|"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value123"] 5 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/03-adult_age_in_user/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": { 3 | "name": "REQUIRED", 4 | "age1": "TOO_LOW", 5 | "age2": "WRONG_AGE" 6 | }, 7 | "user_custom_error": "WRONG_USER" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/08-like/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "like": "[0-9]+" }, 3 | "last_name": { "like": ["^[A-Z]+$"] }, 4 | "age": [{ "like": "^[a-z]+$" }], 5 | "empty_name": { "like": "[A-Za-z]" } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/23-url/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "www.google.com", 3 | "url2": "ftp://facebook.com", 4 | "url3": "http://g_oogle.com", 5 | "empty_field": "", 6 | "extra_field": "aaaa" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/10-positive_integer/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "positive_integer", 3 | "number2": ["positive_integer"], 4 | "number3": [ { "positive_integer": [] } ], 5 | "empty_field": "positive_integer" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/12-positive_decimal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10", 3 | "number2": "120.11", 4 | "number3": "99999.9999", 5 | "number4": "0.01", 6 | "empty_field": "", 7 | "extra_field": "100" 8 | } 9 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/16-email/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "test@mail.com", 3 | "email2": "test.test@mail.com.ua", 4 | "email3": "test+test.t_e_s_t@mail.in.ua", 5 | "empty_field": "", 6 | "extra_field": "aaaa" 7 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.2" 5 | - "3.3" 6 | - "3.4" 7 | # command to install dependencies 8 | install: "pip install pyyaml" 9 | # command to run tests 10 | script: ./LIVR/test/case_handler.py -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/04-min_length/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "min_length": 6 }, 3 | "last_name": { "min_length": [10] }, 4 | "middle_name": [{ "min_length": [10] }], 5 | "empty_name": { "min_length": 3 } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/05-max_length/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "max_length": 4 }, 3 | "last_name": { "max_length": [5] }, 4 | "middle_name": [{ "max_length": [0] }], 5 | "empty_name": { "max_length": 3 } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/24-iso_date/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "2014-13-10", 3 | "iso_date2": "2011-02-29", 4 | "iso_date3": "2014-10-10T22:22", 5 | "empty_field": "", 6 | "extra_field": "aaaa" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/18-nested_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "country": "Russia", 4 | "zip": "AAA", 5 | "street": "", 6 | "building": "-10" 7 | }, 8 | "address2": "Should be hash" 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/27-any_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_string": "any_object", 3 | "value_is_number": "any_object", 4 | "value_is_array": "any_object", 5 | "value_is_empty_array": "any_object" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/04-min_length/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": 1111, 6 | "empty_name": "", 7 | "extra_name": "extra_name" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/05-max_length/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Васек", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": 1111, 6 | "empty_name": "", 7 | "extra_name": "extra_name" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/06-length_equal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": 1111, 6 | "empty_name": "", 7 | "extra_name": "extra_name" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/23-url/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "https://google.com", 3 | "url2": "HTTP://127.0.0.1:3233/?param_1=123¶m_2=asd", 4 | "url3": "http://webbylab.com/?param_1=123#anchor", 5 | "empty_field": "" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/27-any_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "object1": "any_object", 3 | "object2": [{ "any_object": [] }], 4 | "object3": "any_object", 5 | "empty_field": "any_object", 6 | "missed_field": "any_object" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/26-string/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_hash": "FORMAT_ERROR", 3 | "value_is_empty_hash": "FORMAT_ERROR", 4 | "value_is_array": "FORMAT_ERROR", 5 | "value_is_empty_array": "FORMAT_ERROR" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/27-any_object/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "value_is_string": "FORMAT_ERROR", 3 | "value_is_number": "FORMAT_ERROR", 4 | "value_is_array": "FORMAT_ERROR", 5 | "value_is_empty_array": "FORMAT_ERROR" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/07-length_between/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": "Vasya", 3 | "last_name": "Pupkin", 4 | "middle_name": "Some name", 5 | "number1": 1111, 6 | "empty_name": "", 7 | "extra_name": "extra_name" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/31-to_lc/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "Value", 3 | "object": {"string_value": "Some Value"}, 4 | "list_of_string_values": ["VALUE1", {"key": "123"}, "VALUE2"], 5 | "to_lc_with_another_rule": "Value" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/06-length_equal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "length_equal": 2 }, 3 | "last_name": { "length_equal": [7] }, 4 | "middle_name": [{ "length_equal": [3] }], 5 | "empty_name": { "length_equal": 3 } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/24-iso_date/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "2014-02-18", 3 | "iso_date2": "1930-03-30", 4 | "iso_date3": "1930-01-01", 5 | "iso_date4": "1970-01-01", 6 | "empty_field": "", 7 | "extra_field": "aaaa" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/24-iso_date/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "iso_date1": "iso_date", 3 | "iso_date2": { "iso_date": [] }, 4 | "iso_date3": [ { "iso_date": [] } ], 5 | "iso_date4": [ { "iso_date": [] } ], 6 | "empty_field": "iso_date" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/31-to_lc/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "value", 3 | "object": {"string_value": "some value"}, 4 | "list_of_string_values": ["value1", {"key": "123"}, "value2"], 5 | "to_lc_with_another_rule": "value" 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/22-not_empty_list/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "list1": "CANNOT_BE_EMPTY", 3 | "list2": "CANNOT_BE_EMPTY", 4 | "not_list": "FORMAT_ERROR", 5 | "empty_field": "CANNOT_BE_EMPTY", 6 | "missed_field": "CANNOT_BE_EMPTY" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/33-remove/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": {"remove": "V "}, 3 | "object": {"nested_object": { 4 | "string_value": {"remove": "azv|-" } 5 | }}, 6 | "list_of_string_values": {"list_of": {"remove": "2"} } 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/02-address/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "street": "REQUIRED", 4 | "zip": "NOT_POSITIVE_INTEGER", 5 | "city": "NOT_ALLOWED_VALUE" 6 | }, 7 | "address_custom_error": "WRONG_ADDRESS" 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/25-eq/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": { "eq": "Moscow" }, 3 | "city2": [{ "eq": "Kiev" }], 4 | "city3": { "eq": "Kiev" }, 5 | "number1": { "eq": 2 }, 6 | "number2": { "eq": "2" }, 7 | "empty_city": { "eq": "Kiev" } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/31-to_lc/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": "to_lc", 3 | "object": {"nested_object": {"string_value": "to_lc"} }, 4 | "list_of_string_values": {"list_of": "to_lc"}, 5 | "to_lc_with_another_rule": ["to_lc", "required"] 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/19-list_of/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": ["required", { "list_of": [[ 3 | "required", 4 | "positive_integer", 5 | { "max_number": 100 } 6 | ]] }], 7 | "user_ids": { "list_of": [[ "required" ]] } 8 | 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/22-not_empty_list/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "list1": "not_empty_list", 3 | "list2": [{ "not_empty_list" : [] }], 4 | "not_list": "not_empty_list", 5 | "empty_field": "not_empty_list", 6 | "missed_field": ["not_empty_list"] 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/03-one_of/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "Moscow", 3 | "city2": "Kiev", 4 | "city3": "Kiev", 5 | "number1": 2, 6 | "number2": 2, 7 | "boolean": true, 8 | "empty_city": "", 9 | "extra_city": "New York" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/19-list_of/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "product_ids": ["required", { "list_of": [[ 3 | "required", 4 | "positive_integer", 5 | { "max_number": 100 } 6 | ]] }], 7 | "user_ids": { "list_of": [[ "required" ]] } 8 | 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/17-equal_to_field/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": { "equal_to_field": "field2" }, 3 | "field2": { "equal_to_field": ["field1"] }, 4 | "field3": { "equal_to_field": ["field1"] }, 5 | "empty_field": { "equal_to_field": "field2" } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/15-number_between/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "number_between": [10, 20] }, 3 | "number2": { "number_between": [20, 30] }, 4 | "number3": [ { "number_between": [-1, 1] } ], 5 | "empty_field": { "number_between": [10, 20] } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/17-equal_to_field/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "field1": { "equal_to_field": "field2" }, 3 | "field2": { "equal_to_field": ["field1"] }, 4 | "field3": { "equal_to_field": ["field1"] }, 5 | "empty_field": { "equal_to_field": "field2" } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/23-url/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "https://google.com", 3 | "url2": "HTTP://127.0.0.1:3233/?param_1=123¶m_2=asd", 4 | "url3": "http://webbylab.com/?param_1=123#anchor", 5 | "empty_field": "", 6 | "extra_field": "aaaa" 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/34-leave_only/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "string_value": {"leave_only": "Vl "}, 3 | "object": {"nested_object": { 4 | "string_value": {"leave_only": "azv-" } 5 | }}, 6 | "list_of_string_values": {"list_of": {"leave_only": "23"} } 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/07-lenght_between/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "length_between": [7, 10]}, 3 | "last_name": { "length_between": [4, 5] }, 4 | "middle_name": [{ "length_between": [2, 3] }], 5 | "empty_name": { "length_between": [4, 10] } 6 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/12-positive_decimal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "positive_decimal", 3 | "number2": ["positive_decimal"], 4 | "number3": [ { "positive_decimal": [] } ], 5 | "number4": "positive_decimal", 6 | "empty_field": "positive_decimal" 7 | } -------------------------------------------------------------------------------- /LIVR/Rules/constants.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | OBJECTS_LIST = (list, dict) 4 | NUMBER_LIST = (int, float) 5 | PRIMITIVE_LIST = NUMBER_LIST + (str, bool) 6 | EMPTY_PRIMITIVE = lambda x: x == None or x == '' 7 | 8 | if sys.version_info[0] < 3: 9 | PRIMITIVE_LIST += (unicode,) 10 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/01-adult_age/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "age1": 32, 3 | "age2": 33, 4 | "age3": 35, 5 | "age4": 36, 6 | "age1_custom_error": 37, 7 | "age2_custom_error": 38, 8 | "age3_custom_error": 100, 9 | "age4_custom_error": 110 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/18-nested_object/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "country": "NOT_ALLOWED_VALUE", 4 | "zip": "NOT_POSITIVE_INTEGER", 5 | "street": "REQUIRED", 6 | "building": "NOT_POSITIVE_INTEGER" 7 | }, 8 | "address2": "FORMAT_ERROR" 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/18-nested_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "country": "Ukraine", 4 | "zip": "12345", 5 | "street": "10", 6 | "building": "10", 7 | "extra_field": "will be removed" 8 | }, 9 | "extra_field": "will be removed" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/03-adult_age_in_user/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": { 3 | "name": "koorchik", 4 | "age1": 20, 5 | "age2": 40 6 | }, 7 | "user_custom_error": { 8 | "name": "koorchik", 9 | "age1": 33, 10 | "age2": 22 11 | } 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/20-list_of_objects/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ "required", { "list_of_objects": { 3 | "product_id": [ "required","positive_integer" ], 4 | "quantity": [ "required", "positive_integer" ] 5 | }}], 6 | "users": {"list_of_objects" : {"name": "required"} } 7 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/01-adult_age/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "age1": 32, 3 | "age2": 33, 4 | "age3": 15, 5 | "age4": -20, 6 | "age1_custom_error": 37, 7 | "age2_custom_error": 38, 8 | "age3_custom_error": 16, 9 | "age4_custom_error": -10, 10 | "extra_field": 12 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/01-adult_age/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "age1": 32, 3 | "age2": 33, 4 | "age3": 35, 5 | "age4": 36, 6 | "age1_custom_error": 37, 7 | "age2_custom_error": 38, 8 | "age3_custom_error": 100, 9 | "age4_custom_error": 110, 10 | "extra_field": 12 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/04-min_length/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "min_length": 3 }, 3 | "last_name": { "min_length": [4] }, 4 | "middle_name": [{ "min_length": [5] }], 5 | "number1": {"min_length": 2}, 6 | "empty_name": { "min_length": 3 }, 7 | "missed_name": { "min_length": 3 } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/02-address/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "street": "My street", 4 | "zip": 1232131, 5 | "city": "Kiev" 6 | }, 7 | "address_custom_error": { 8 | "street": "My street", 9 | "zip": 12312, 10 | "city": "Kharkiv" 11 | } 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/05-max_length/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "max_length": 5 }, 3 | "last_name": { "max_length": [10] }, 4 | "middle_name": [{ "max_length": [10] }], 5 | "number1": { "max_length": 5 }, 6 | "empty_name": { "max_length": 3 }, 7 | "missed_name": { "max_length": 3 } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/18-nested_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": [ "required", { "nested_object": { 3 | "country": ["required", { "one_of": [["Ukraine", "USA"]] } ], 4 | "zip": "positive_integer", 5 | "street": "required", 6 | "building": ["required", "positive_integer" ] 7 | } } ] 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/23-url/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "WRONG_URL", 3 | "url2": "WRONG_URL", 4 | "url3": "WRONG_URL", 5 | 6 | "value_is_hash": "FORMAT_ERROR", 7 | "value_is_empty_hash": "FORMAT_ERROR", 8 | "value_is_array": "FORMAT_ERROR", 9 | "value_is_empty_array": "FORMAT_ERROR" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/23-url/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "url", 3 | "url2": { "url": [] }, 4 | "url3": [ { "url": [] } ], 5 | "empty_field": "url", 6 | 7 | "value_is_hash": "url", 8 | "value_is_empty_hash": "url", 9 | "value_is_array": "url", 10 | "value_is_empty_array": "url" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/06-length_equal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "length_equal": 5 }, 3 | "last_name": { "length_equal": [6] }, 4 | "middle_name": [{ "length_equal": [9] }], 5 | "number1": { "length_equal": 4 }, 6 | "empty_name": { "length_equal": 3 }, 7 | "missed_name": { "length_equal": 3 } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/08-like/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "like": "[A-Za-z]+" }, 3 | "last_name": { "like": ["^[A-Za-z]+$"] }, 4 | "middle_name": { "like": ["^[a-z]+$", "i"] }, 5 | "age": [{ "like": "^[0-9]+$" }], 6 | "empty_name": { "like": "[A-Za-z]" }, 7 | "missed_name": { "like": "[A-Za-z]" } 8 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/02-address/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "street": "", 4 | "zip": -1232131, 5 | "city": "Moscow" 6 | }, 7 | "address_custom_error": { 8 | "street": "My street", 9 | "zip": "12312", 10 | "city": "Moscow" 11 | }, 12 | "extra_field": 12 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/02-address/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": { 3 | "street": "My street", 4 | "zip": 1232131, 5 | "city": "Kiev" 6 | }, 7 | "address_custom_error": { 8 | "street": "My street", 9 | "zip": "12312", 10 | "city": "Kharkiv" 11 | }, 12 | "extra_field": 12 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/20-list_of_objects/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ "required", { "list_of_objects": { 3 | "product_id": [ "required","positive_integer" ], 4 | "quantity": [ "required", "positive_integer" ] 5 | }}], 6 | 7 | "empty_list": [{"list_of_objects": { 8 | "some_field": ["required"] 9 | }}] 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/01-adult_age/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "adult_age", 4 | "rules": ["positive_integer", {"min_number": 18}] 5 | }, 6 | 7 | { 8 | "name": "adult_age_with_custom_error", 9 | "rules": ["positive_integer", {"min_number": 18}], 10 | "error": "WRONG_AGE" 11 | } 12 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/01-adult_age/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "adult_age", 4 | "rules": ["positive_integer", {"min_number": 18}] 5 | }, 6 | 7 | { 8 | "name": "adult_age_with_custom_error", 9 | "rules": ["positive_integer", {"min_number": 18}], 10 | "error": "WRONG_AGE" 11 | } 12 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/03-adult_age_in_user/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": { 3 | "name": "", 4 | "age1": 15, 5 | "age2": 15, 6 | "extra_field": "som value" 7 | }, 8 | "user_custom_error": { 9 | "name": "koorchik", 10 | "age1": 15, 11 | "age2": 22 12 | }, 13 | "extra_field": 12 14 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/13-max_number/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "TOO_HIGH", 3 | "number2": "TOO_HIGH", 4 | 5 | "value_is_string": "NOT_NUMBER", 6 | "value_is_hash": "FORMAT_ERROR", 7 | "value_is_empty_hash": "FORMAT_ERROR", 8 | "value_is_array": "FORMAT_ERROR", 9 | "value_is_empty_array": "FORMAT_ERROR" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/14-min_number/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "TOO_LOW", 3 | "number2": "TOO_LOW", 4 | 5 | "value_is_string": "NOT_NUMBER", 6 | "value_is_hash": "FORMAT_ERROR", 7 | "value_is_empty_hash": "FORMAT_ERROR", 8 | "value_is_array": "FORMAT_ERROR", 9 | "value_is_empty_array": "FORMAT_ERROR" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/25-eq/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "New York", 3 | "city2": "New York", 4 | "city3": "New York", 5 | "number1": "1.0", 6 | "extra_city": "New York", 7 | 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/03-one_of/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "New York", 3 | "city2": "New York", 4 | "city3": "New York", 5 | "number1": "1.0", 6 | "extra_city": "New York", 7 | 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/15-number_beetween/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "TOO_LOW", 3 | "number2": "TOO_HIGH", 4 | 5 | "value_is_string": "NOT_NUMBER", 6 | "value_is_hash": "FORMAT_ERROR", 7 | "value_is_empty_hash": "FORMAT_ERROR", 8 | "value_is_array": "FORMAT_ERROR", 9 | "value_is_empty_array": "FORMAT_ERROR" 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/29-or/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": "NOT_POSITIVE_INTEGER", 3 | "id2-1": "NOT_POSITIVE_INTEGER", 4 | "id3-1": "WRONG_EMAIL", 5 | "products": [ 6 | { 7 | "name": "REQUIRED", 8 | "product_type": "NOT_ALLOWED_VALUE" 9 | }, 10 | { 11 | "name": "REQUIRED" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/03-adult_age_in_user/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "user": { 3 | "name": "koorchik", 4 | "age1": 20, 5 | "age2": 40, 6 | "extra_field": "som value" 7 | }, 8 | "user_custom_error": { 9 | "name": "koorchik", 10 | "age1": 33, 11 | "age2": 22 12 | }, 13 | "extra_field": 12 14 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/14-min_number/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "5", 3 | "number2": "-10", 4 | "empty_field": "", 5 | "extra_field": "100", 6 | 7 | "value_is_string": "some_string", 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/13-max_number/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "15", 3 | "number2": "25.5", 4 | "empty_field": "", 5 | "extra_field": "100", 6 | 7 | "value_is_string": "some_string", 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/15-number_beetween/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "5", 3 | "number2": "40", 4 | "empty_field": "", 5 | "extra_field": "100", 6 | 7 | "value_is_string": "some_string", 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/20-list_of_objects/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "product_id": "NOT_POSITIVE_INTEGER", 5 | "quantity": "REQUIRED" 6 | }, 7 | null, 8 | { 9 | "product_id": "NOT_POSITIVE_INTEGER" 10 | }, 11 | "FORMAT_ERROR" 12 | ], 13 | "users": "FORMAT_ERROR" 14 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/07-length_between/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "first_name": { "length_between": [4, 6] }, 3 | "last_name": { "length_between": [6, 6] }, 4 | "middle_name": [{ "length_between": [0, 100] }], 5 | "number1": { "length_between": [2, 4] }, 6 | "empty_name": { "length_between": [2, 3] }, 7 | "missed_name": { "length_between": [2, 3] } 8 | } 9 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/23-url/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "url1": "www.google.com", 3 | "url2": "ftp://facebook.com", 4 | "url3": "http://g_oogle.com", 5 | "empty_field": "", 6 | "extra_field": "aaaa", 7 | 8 | "value_is_hash": {"test": 1}, 9 | "value_is_empty_hash": {}, 10 | "value_is_array": ["test", 1], 11 | "value_is_empty_array": [] 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/18-nested_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": [ "required", { "nested_object": { 3 | "country": ["required", { "one_of": [["Ukraine", "USA"]] } ], 4 | "zip": "positive_integer", 5 | "street": "required", 6 | "building": ["required", "positive_integer" ] 7 | } } ], 8 | "address2": { "nested_object": { "country": "required" } } 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/03-one_of/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": { "one_of": [["Moscow", "Kiev" ]] }, 3 | "city2": [{ "one_of": [["Moscow", "Kiev" ]] }], 4 | "city3": { "one_of": ["Moscow", "Kiev"] }, 5 | "number1": { "one_of": [1, 2] }, 6 | "number2": { "one_of": ["1", "2"] }, 7 | "boolean": { "one_of": [true, false] }, 8 | "empty_city": { "one_of": [["Moscow", "Kiev" ]] } 9 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/09-integer/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "NOT_INTEGER", 3 | "number2": "NOT_INTEGER", 4 | "number3": "NOT_INTEGER", 5 | 6 | "value_is_string": "NOT_INTEGER", 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/09-integer/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "A", 3 | "number2": "0.12", 4 | "number3": -1.12, 5 | "empty_field": "", 6 | "extra_field": "100", 7 | 8 | "value_is_string": "some_string", 9 | "value_is_hash": {"test": 1}, 10 | "value_is_empty_hash": {}, 11 | "value_is_array": ["test", 1], 12 | "value_is_empty_array": [] 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/11-decimal/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "NOT_DECIMAL", 3 | "number2": "NOT_DECIMAL", 4 | "number3": "NOT_DECIMAL", 5 | 6 | "value_is_string": "NOT_DECIMAL", 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/25-eq/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "NOT_ALLOWED_VALUE", 3 | "city2": "NOT_ALLOWED_VALUE", 4 | "city3": "NOT_ALLOWED_VALUE", 5 | "number1": "NOT_ALLOWED_VALUE", 6 | 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/03-one_of/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": "NOT_ALLOWED_VALUE", 3 | "city2": "NOT_ALLOWED_VALUE", 4 | "city3": "NOT_ALLOWED_VALUE", 5 | "number1": "NOT_ALLOWED_VALUE", 6 | 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/11-decimal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "A", 3 | "number2": "12.12.12", 4 | "number3": "1,12", 5 | "empty_field": "", 6 | "extra_field": "100", 7 | 8 | "value_is_string": "some_string", 9 | "value_is_hash": {"test": 1}, 10 | "value_is_empty_hash": {}, 11 | "value_is_array": ["test", 1], 12 | "value_is_empty_array": [] 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/25-eq/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": { "eq": "Moscow" }, 3 | "city2": [{ "eq": "Moscow" }], 4 | "city3": { "eq": "Kiev" }, 5 | "number1": { "eq": 1 }, 6 | 7 | "value_is_hash": { "eq": "Moscow" }, 8 | "value_is_empty_hash": { "eq": "Moscow" }, 9 | "value_is_array": { "eq": "Moscow" }, 10 | "value_is_empty_array": { "eq": "Moscow" } 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/20-list_of_objects/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "product_id": 10, 5 | "quantity": 10 6 | }, 7 | { 8 | "product_id": 20, 9 | "quantity": 20 10 | }, 11 | { 12 | "product_id": 30, 13 | "quantity": 30 14 | } 15 | ], 16 | "empty_list": [] 17 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/09-integer/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "integer", 3 | "number2": ["integer"], 4 | "number3": [ { "integer": [] } ], 5 | "empty_field": "integer", 6 | 7 | "value_is_string": "integer", 8 | "value_is_hash": "integer", 9 | "value_is_empty_hash": "integer", 10 | "value_is_array": "integer", 11 | "value_is_empty_array": "integer" 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/10-positive_integer/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "A", 3 | "number2": "-10", 4 | "number3": "0", 5 | "empty_field": "", 6 | "extra_field": "100", 7 | 8 | "value_is_string": "some_string", 9 | "value_is_hash": {"test": 1}, 10 | "value_is_empty_hash": {}, 11 | "value_is_array": ["test", 1], 12 | "value_is_empty_array": [] 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/11-decimal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "decimal", 3 | "number2": ["decimal"], 4 | "number3": [ { "decimal": [] } ], 5 | "empty_field": "decimal", 6 | 7 | "value_is_string": "decimal", 8 | "value_is_hash": "decimal", 9 | "value_is_empty_hash": "decimal", 10 | "value_is_array": "decimal", 11 | "value_is_empty_array": "decimal" 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/16-email/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "email", 3 | "email2": { "email": [] }, 4 | "email3": [ { "email": [] } ], 5 | "email4": "email", 6 | "email5": "email", 7 | "empty_field": "email", 8 | 9 | "value_is_hash": "email", 10 | "value_is_empty_hash": "email", 11 | "value_is_array": "email", 12 | "value_is_empty_array": "email" 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/20-list_of_objects/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "product_id": 10, 5 | "quantity": "10" 6 | }, 7 | { 8 | "product_id": 20, 9 | "quantity": 20 10 | }, 11 | { 12 | "product_id": 30, 13 | "quantity": 30 14 | } 15 | ], 16 | "empty_list": [] 17 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/12-positive_decimal/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "10.10.10", 3 | "number2": "0", 4 | "number3": -1.12, 5 | "empty_field": "", 6 | "extra_field": "100", 7 | 8 | "value_is_string": "some_string", 9 | "value_is_hash": {"test": 1}, 10 | "value_is_empty_hash": {}, 11 | "value_is_array": ["test", 1], 12 | "value_is_empty_array": [] 13 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/16-email/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "WRONG_EMAIL", 3 | "email2": "WRONG_EMAIL", 4 | "email3": "WRONG_EMAIL", 5 | "email4": "WRONG_EMAIL", 6 | "email5": "WRONG_EMAIL", 7 | 8 | "value_is_hash": "FORMAT_ERROR", 9 | "value_is_empty_hash": "FORMAT_ERROR", 10 | "value_is_array": "FORMAT_ERROR", 11 | "value_is_empty_array": "FORMAT_ERROR" 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/10-positive_integer/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "NOT_POSITIVE_INTEGER", 3 | "number2": "NOT_POSITIVE_INTEGER", 4 | "number3": "NOT_POSITIVE_INTEGER", 5 | 6 | "value_is_string": "NOT_POSITIVE_INTEGER", 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/12-positive_decimal/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "NOT_POSITIVE_DECIMAL", 3 | "number2": "NOT_POSITIVE_DECIMAL", 4 | "number3": "NOT_POSITIVE_DECIMAL", 5 | 6 | "value_is_string": "NOT_POSITIVE_DECIMAL", 7 | "value_is_hash": "FORMAT_ERROR", 8 | "value_is_empty_hash": "FORMAT_ERROR", 9 | "value_is_array": "FORMAT_ERROR", 10 | "value_is_empty_array": "FORMAT_ERROR" 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/20-list_of_objects/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "products": [ 3 | { 4 | "product_id": 0, 5 | "quantity": "" 6 | }, 7 | { 8 | "product_id": 100, 9 | "quantity": 10 10 | }, 11 | { 12 | "product_id": -10, 13 | "quantity": 10 14 | }, 15 | "Some Wrong Data" 16 | ], 17 | "users": "not an array" 18 | } -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | # file GENERATED by distutils, do NOT edit 2 | README.rst 3 | setup.py 4 | LIVR/BuildAliasedRule.py 5 | LIVR/DEFAULT_RULES.py 6 | LIVR/Validator.py 7 | LIVR/__init__.py 8 | LIVR/Rules/Common.py 9 | LIVR/Rules/Filters.py 10 | LIVR/Rules/Helper.py 11 | LIVR/Rules/Numeric.py 12 | LIVR/Rules/Special.py 13 | LIVR/Rules/String.py 14 | LIVR/Rules/__init__.py 15 | LIVR/test/__init__.py 16 | LIVR/test/case_handler.py 17 | LIVR/test/test_suite.py 18 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/28-variable_object/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "NOT_POSITIVE_INTEGER", 3 | "product1": { 4 | "material_id": "NOT_POSITIVE_INTEGER", 5 | "quantity": "REQUIRED" 6 | }, 7 | "product2": { 8 | "warehouse_id": "NOT_POSITIVE_INTEGER" 9 | }, 10 | "product3": { 11 | "name": "TOO_LONG" 12 | }, 13 | "product4": "FORMAT_ERROR", 14 | "product5": "FORMAT_ERROR" 15 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/01-adult_age/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "age1": "adult_age", 3 | "age2": ["adult_age"], 4 | "age3": [ { "adult_age": [] } ], 5 | "age4": { "adult_age": [] }, 6 | "age1_custom_error": "adult_age_with_custom_error", 7 | "age2_custom_error": ["adult_age_with_custom_error"], 8 | "age3_custom_error": [ { "adult_age_with_custom_error": [] } ], 9 | "age4_custom_error": { "adult_age_with_custom_error": [] } 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/01-adult_age/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "age1": "adult_age", 3 | "age2": ["adult_age"], 4 | "age3": [ { "adult_age": [] } ], 5 | "age4": { "adult_age": [] }, 6 | "age1_custom_error": "adult_age_with_custom_error", 7 | "age2_custom_error": ["adult_age_with_custom_error"], 8 | "age3_custom_error": [ { "adult_age_with_custom_error": [] } ], 9 | "age4_custom_error": { "adult_age_with_custom_error": [] } 10 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/13-max_number/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "max_number": 10 }, 3 | "number2": [{ "max_number": 20 }], 4 | "empty_field": { "max_number": 40 }, 5 | 6 | "value_is_string": { "max_number": 10 }, 7 | "value_is_hash": { "max_number": 10 }, 8 | "value_is_empty_hash": { "max_number": 10 }, 9 | "value_is_array": { "max_number": 10 }, 10 | "value_is_empty_array": { "max_number": 10 } 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/14-min_number/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "min_number" : 10 }, 3 | "number2": [{ "min_number" : 20 }], 4 | "empty_field": { "min_number" : 10 }, 5 | 6 | "value_is_string": { "min_number": 10 }, 7 | "value_is_hash": { "min_number": 10 }, 8 | "value_is_empty_hash": { "min_number": 10 }, 9 | "value_is_array": { "min_number": 10 }, 10 | "value_is_empty_array": { "min_number": 10 } 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/29-or/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": "Usermail.com", 3 | "id2-1": "Usermail.com", 4 | "id3-1": "Usermail.com", 5 | 6 | "products": [ 7 | { 8 | "product_type": "material", 9 | "material_id": 123, 10 | "quantity": 10, 11 | "warehouse_id": -321 12 | }, 13 | 14 | { 15 | "product_type": "service", 16 | "name": "", 17 | "extra_field": "some data" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/16-email/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "email1": "testmail.com", 3 | "email2": "test@test@mail.com.ua", 4 | "email3": "test+test.t_e_s_t@ma_il.in.ua", 5 | "email4": "user name@gmail.com", 6 | "email5": "username@mail.c om", 7 | "empty_field": "", 8 | "extra_field": "aaaa", 9 | 10 | "value_is_hash": {"test": 1}, 11 | "value_is_empty_hash": {}, 12 | "value_is_array": ["test", 1], 13 | "value_is_empty_array": [] 14 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/21-list_of_different_objects/errors.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "NOT_POSITIVE_INTEGER", 3 | "products": [ 4 | { 5 | "material_id": "NOT_POSITIVE_INTEGER", 6 | "quantity": "REQUIRED" 7 | }, 8 | { 9 | "warehouse_id": "NOT_POSITIVE_INTEGER" 10 | }, 11 | { 12 | "name": "TOO_LONG" 13 | }, 14 | "FORMAT_ERROR", 15 | "FORMAT_ERROR" 16 | ] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/28-variable_object/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": 10, 3 | "product1": { 4 | "product_type": "material", 5 | "material_id": 12, 6 | "quantity": 11 7 | }, 8 | "product2": { 9 | "product_type": "material", 10 | "material_id": 100, 11 | "quantity": 10, 12 | "warehouse_id": 100 13 | }, 14 | "product3": { 15 | "product_type": "service", 16 | "name": "service1" 17 | } 18 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/10-positive_integer/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "positive_integer", 3 | "number2": ["positive_integer"], 4 | "number3": [ { "positive_integer": [] } ], 5 | "empty_field": "positive_integer", 6 | 7 | "value_is_string": "positive_integer", 8 | "value_is_hash": "positive_integer", 9 | "value_is_empty_hash": "positive_integer", 10 | "value_is_array": "positive_integer", 11 | "value_is_empty_array": "positive_integer" 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/12-positive_decimal/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": "positive_decimal", 3 | "number2": ["positive_decimal"], 4 | "number3": [ { "positive_decimal": [] } ], 5 | "empty_field": "positive_decimal", 6 | 7 | "value_is_string": "positive_decimal", 8 | "value_is_hash": "positive_decimal", 9 | "value_is_empty_hash": "positive_decimal", 10 | "value_is_array": "positive_decimal", 11 | "value_is_empty_array": "positive_decimal" 12 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/15-number_beetween/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "number1": { "number_between": [10,20] }, 3 | "number2": [ { "number_between": [10,20] } ], 4 | "empty_field": { "number_between": [10,20] }, 5 | 6 | "value_is_string": { "number_between": [10,20] }, 7 | "value_is_hash": { "number_between": [10,20] }, 8 | "value_is_empty_hash": { "number_between": [10,20] }, 9 | "value_is_array": { "number_between": [10,20] }, 10 | "value_is_empty_array": { "number_between": [10,20] } 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/28-variable_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "10", 3 | "product1": { 4 | "product_type": "material", 5 | "material_id": 12, 6 | "quantity": "11" 7 | }, 8 | "product2": { 9 | "product_type": "material", 10 | "material_id": 100, 11 | "quantity": 10, 12 | "warehouse_id": 100 13 | }, 14 | "product3": { 15 | "product_type": "service", 16 | "name": "service1", 17 | "extra_field": "will be removed" 18 | } 19 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/03-one_of/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "city1": { "one_of": [["Moscow", "Kiev" ]] }, 3 | "city2": [{ "one_of": [["Moscow", "Kiev" ]] }], 4 | "city3": { "one_of": ["Moscow", "Kiev"] }, 5 | "number1": { "one_of": [1, "1.00", "1"] }, 6 | 7 | "value_is_hash": { "one_of": [["Moscow", "Kiev" ]] }, 8 | "value_is_empty_hash": { "one_of": [["Moscow", "Kiev" ]] }, 9 | "value_is_array": { "one_of": [["Moscow", "Kiev" ]] }, 10 | "value_is_empty_array": { "one_of": [["Moscow", "Kiev" ]] } 11 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/29-or/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": "User@mail.com", 3 | "id1-2": 123, 4 | 5 | "id2-1": "user1@mail.com", 6 | "id2-2": "1234", 7 | 8 | "id3-1": "user@mail.com", 9 | "id3-2": "UserUserUser@mail.com", 10 | 11 | "products": [ 12 | { 13 | "product_type": "material", 14 | "material_id": 123, 15 | "quantity": 10, 16 | "warehouse_id": 321 17 | }, 18 | 19 | { 20 | "product_type": "service", 21 | "name": "Some service" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/21-list_of_different_objects/output.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": 10, 3 | "products": [ 4 | { 5 | "product_type": "material", 6 | "material_id": 12, 7 | "quantity": 11 8 | }, 9 | { 10 | "product_type": "material", 11 | "material_id": 100, 12 | "quantity": 10, 13 | "warehouse_id": 100 14 | }, 15 | { 16 | "product_type": "service", 17 | "name": "service1" 18 | } 19 | ], 20 | "empty_list": [] 21 | } -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from codecs import open 3 | from os import path 4 | 5 | here = path.abspath(path.dirname(__file__)) 6 | 7 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 8 | long_description = f.read() 9 | setup( 10 | name='LIVR', 11 | version='2.0.1', 12 | author='Ihor Kolosha, Viktor Turstkiy', 13 | packages=find_packages(), 14 | license='look into README', 15 | description='LIVR validator.', 16 | long_description=long_description, 17 | url='https://github.com/asholok/python-validator-livr' 18 | ) -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/29-or/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": "User@mail.com", 3 | "id1-2": 123, 4 | 5 | "id2-1": "User1@mail.com", 6 | "id2-2": 1234, 7 | 8 | "id3-1": "User@mail.com", 9 | "id3-2": "UserUserUser@mail.com", 10 | 11 | "products": [ 12 | { 13 | "product_type": "material", 14 | "material_id": 123, 15 | "quantity": 10, 16 | "warehouse_id": 321 17 | }, 18 | 19 | { 20 | "product_type": "service", 21 | "name": "Some service", 22 | "extra_field": "some data" 23 | } 24 | ] 25 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/21-list_of_different_objects/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "10", 3 | "products": [ 4 | { 5 | "product_type": "material", 6 | "material_id": 12, 7 | "quantity": "11" 8 | }, 9 | { 10 | "product_type": "material", 11 | "material_id": 100, 12 | "quantity": 10, 13 | "warehouse_id": 100 14 | }, 15 | { 16 | "product_type": "service", 17 | "name": "service1", 18 | "extra_field": "will be removed" 19 | } 20 | ], 21 | "empty_list": [] 22 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/02-address/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "address", 4 | "rules": { "nested_object":{ 5 | "street": "required", 6 | "zip": ["required", "positive_integer"], 7 | "city": {"one_of": ["Kiev", "Kharkiv"] } 8 | }} 9 | }, 10 | 11 | { 12 | "name": "address_with_custom_error", 13 | "rules": { "nested_object":{ 14 | "street": "required", 15 | "zip": ["required", "positive_integer"], 16 | "city": {"one_of": ["Kiev", "Kharkiv"] } 17 | }}, 18 | "error": "WRONG_ADDRESS" 19 | } 20 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/02-address/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "address", 4 | "rules": { "nested_object":{ 5 | "street": "required", 6 | "zip": ["required", "positive_integer"], 7 | "city": {"one_of": [["Kiev", "Kharkiv"]] } 8 | }} 9 | }, 10 | 11 | { 12 | "name": "address_with_custom_error", 13 | "rules": { "nested_object":{ 14 | "street": "required", 15 | "zip": ["required", "positive_integer"], 16 | "city": {"one_of": [["Kiev", "Kharkiv"]] } 17 | }}, 18 | "error": "WRONG_ADDRESS" 19 | } 20 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/28-variable_object/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "-10", 3 | "product1": { 4 | "product_type": "material", 5 | "material_id": 0, 6 | "quantity": "" 7 | }, 8 | "product2": { 9 | "product_type": "material", 10 | "material_id": 100, 11 | "quantity": 10, 12 | "warehouse_id": -100 13 | }, 14 | "product3": { 15 | "product_type": "service", 16 | "name": "Very Long Name" 17 | }, 18 | "product4": { 19 | "product_type": "wrongtype", 20 | "name": "Wrongtype" 21 | }, 22 | "product5": "Some Wrong Data", 23 | "users": "not an array" 24 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/21-list_of_different_objects/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": ["required", "positive_integer"], 3 | "products": ["required", { "list_of_different_objects": [ 4 | "product_type", { 5 | "material": { 6 | "product_type": "required", 7 | "material_id": ["required", "positive_integer"], 8 | "quantity": ["required", {"min_number": 1} ], 9 | "warehouse_id": "positive_integer" 10 | }, 11 | "service": { 12 | "product_type": "required", 13 | "name": ["required", {"max_length": 10} ] 14 | } 15 | } 16 | ]}] 17 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/21-list_of_different_objects/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": "-10", 3 | "products": [ 4 | { 5 | "product_type": "material", 6 | "material_id": 0, 7 | "quantity": "" 8 | }, 9 | { 10 | "product_type": "material", 11 | "material_id": 100, 12 | "quantity": 10, 13 | "warehouse_id": -100 14 | }, 15 | { 16 | "product_type": "service", 17 | "name": "Very Long Name" 18 | }, 19 | { 20 | "product_type": "wrongtype", 21 | "name": "Wrongtype" 22 | }, 23 | "Some Wrong Data" 24 | ], 25 | "users": "not an array" 26 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/29-or/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": { "or": ["email", "positive_integer" ] }, 3 | "id2-1": [{ "or": ["email", "positive_integer" ] }, "to_lc"], 4 | "id3-1": { "or": [{"min_length": 15}, ["email", "to_lc"] ] }, 5 | 6 | "products": {"list_of": { "or": [ 7 | {"nested_object": { 8 | "product_type": ["required", {"eq": "material"}], 9 | "material_id": ["required", "positive_integer"], 10 | "quantity": ["required", {"min_number": 1} ], 11 | "warehouse_id": "positive_integer" 12 | }}, 13 | 14 | {"nested_object": { 15 | "product_type": ["required", {"eq": "service"}], 16 | "name": ["required", {"max_length": 20} ] 17 | }} 18 | ]}} 19 | } -------------------------------------------------------------------------------- /LIVR.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | README.rst 2 | setup.py 3 | LIVR/BuildAliasedRule.py 4 | LIVR/DEFAULT_RULES.py 5 | LIVR/Validator.py 6 | LIVR/__init__.py 7 | LIVR/internal_reactor.py 8 | LIVR.egg-info/PKG-INFO 9 | LIVR.egg-info/SOURCES.txt 10 | LIVR.egg-info/dependency_links.txt 11 | LIVR.egg-info/top_level.txt 12 | LIVR/Rules/Common.py 13 | LIVR/Rules/Meta.py 14 | LIVR/Rules/Modifiers.py 15 | LIVR/Rules/Numeric.py 16 | LIVR/Rules/Special.py 17 | LIVR/Rules/String.py 18 | LIVR/Rules/__init__.py 19 | LIVR/Rules/constants.py 20 | LIVR/test/__init__.py 21 | LIVR/test/case_handler.py 22 | LIVR/test/livr_test.py 23 | LIVR/test/test_suite.py 24 | LIVR/test/test_suite/__init__.py 25 | LIVR/test/test_suite/aliases_negative/__init__.py 26 | LIVR/test/test_suite/aliases_negative/01-adult_age/__init__.py -------------------------------------------------------------------------------- /LIVR/test/livr_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | import yaml 4 | 5 | class TestSuite(unittest.TestCase): 6 | def runTest(self, path, core): 7 | for root, dirs, files in os.walk(path): 8 | self._curent_test = ''.join(root.split('/')[-1]) 9 | files_path = ['/'.join([root,file_name]) for file_name in files] 10 | result = core(self._prepare(files_path), self._curent_test) 11 | 12 | if result: 13 | self.assertEqual(*result) 14 | 15 | def _prepare(self, files_path): 16 | data = {} 17 | 18 | for path in files_path: 19 | name_in_dict = ''.join(path.split('/')[-1]).replace('.json', '') 20 | with open(path) as f: 21 | data[name_in_dict] = yaml.load(f) 22 | 23 | return data 24 | -------------------------------------------------------------------------------- /LIVR/test/test_suite.py: -------------------------------------------------------------------------------- 1 | import os 2 | import yaml 3 | import unittest 4 | 5 | class TestSuite(unittest.TestCase): 6 | def runTest(self, path, core): 7 | for root, dirs, files in os.walk(path): 8 | self._curent_test = ''.join(root.split('/')[-1]) 9 | files_path = ['/'.join([root,file_name]) for file_name in files] 10 | result = core(self._prepare(files_path), self._curent_test) 11 | 12 | if result: 13 | self.assertEqual(*result) 14 | 15 | def _prepare(self, files_path): 16 | data = {} 17 | 18 | for path in files_path: 19 | name_in_dict = ''.join(path.split('/')[-1]).replace('.json', '') 20 | with open(path) as f: 21 | data[name_in_dict] = yaml.load(f) 22 | 23 | return data 24 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_negative/03-adult_age_in_user/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "adult_age", 4 | "rules": ["positive_integer", {"min_number": 18}] 5 | }, 6 | 7 | { 8 | "name": "adult_age_with_custom_error", 9 | "rules": ["positive_integer", {"min_number": 18}], 10 | "error": "WRONG_AGE" 11 | }, 12 | 13 | { 14 | "name": "user", 15 | "rules": { "nested_object":{ 16 | "name": "required", 17 | "age1": "adult_age", 18 | "age2": "adult_age_with_custom_error" 19 | }} 20 | }, 21 | 22 | { 23 | "name": "user_with_custom_error", 24 | "rules": { "nested_object":{ 25 | "name": "required", 26 | "age1": "adult_age", 27 | "age2": "adult_age_with_custom_error" 28 | }}, 29 | "error": "WRONG_USER" 30 | } 31 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/aliases_positive/03-adult_age_in_user/aliases.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "adult_age", 4 | "rules": ["positive_integer", {"min_number": 18}] 5 | }, 6 | 7 | { 8 | "name": "adult_age_with_custom_error", 9 | "rules": ["positive_integer", {"min_number": 18}], 10 | "error": "WRONG_AGE" 11 | }, 12 | 13 | { 14 | "name": "user", 15 | "rules": { "nested_object":{ 16 | "name": "required", 17 | "age1": "adult_age", 18 | "age2": "adult_age_with_custom_error" 19 | }} 20 | }, 21 | 22 | { 23 | "name": "user_with_custom_error", 24 | "rules": { "nested_object":{ 25 | "name": "required", 26 | "age1": "adult_age", 27 | "age2": "adult_age_with_custom_error" 28 | }}, 29 | "error": "WRONG_USER" 30 | } 31 | ] -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/29-or/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "id1-1": { "or": ["email", "positive_integer" ] }, 3 | "id1-2": { "or": ["email", "positive_integer" ] }, 4 | 5 | "id2-1": [{ "or": ["email", "positive_integer" ] }, "to_lc"], 6 | "id2-2": [{ "or": ["email", "positive_integer" ] }, "to_lc"], 7 | 8 | "id3-1": { "or": [{"min_length": 15}, ["email", "to_lc"] ] }, 9 | "id3-2": { "or": [{"min_length": 15}, ["email", "to_lc"] ] }, 10 | 11 | "products": {"list_of": { "or": [ 12 | {"nested_object": { 13 | "product_type": ["required", {"eq": "material"}], 14 | "material_id": ["required", "positive_integer"], 15 | "quantity": ["required", {"min_number": 1} ], 16 | "warehouse_id": "positive_integer" 17 | }}, 18 | 19 | {"nested_object": { 20 | "product_type": ["required", {"eq": "service"}], 21 | "name": ["required", {"max_length": 20} ] 22 | }} 23 | ]}} 24 | 25 | } -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/21-list_of_different_objects/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": ["required", "positive_integer"], 3 | "products": ["required", { "list_of_different_objects": [ 4 | "product_type", { 5 | "material": { 6 | "product_type": "required", 7 | "material_id": ["required", "positive_integer"], 8 | "quantity": ["required", {"min_number": 1} ], 9 | "warehouse_id": "positive_integer" 10 | }, 11 | "service": { 12 | "product_type": "required", 13 | "name": ["required", {"max_length": 10} ] 14 | } 15 | } 16 | ]}], 17 | "empty_list": ["required", { "list_of_different_objects": [ 18 | "item_type", { 19 | "string": { 20 | "value": "required" 21 | }, 22 | "number": { 23 | "value": ["required", "integer" ] 24 | } 25 | } 26 | ]}] 27 | } -------------------------------------------------------------------------------- /LIVR/Validator.py: -------------------------------------------------------------------------------- 1 | try: 2 | import BuildAliasedRule 3 | import DEFAULT_RULES 4 | import internal_reactor 5 | except ImportError: 6 | from . import internal_reactor 7 | from . import BuildAliasedRule 8 | from . import DEFAULT_RULES 9 | 10 | class Validator(internal_reactor.InternalValidator): 11 | def __init__(self, livr_rules, is_auto_trim=False): 12 | super(Validator, self).__init__(livr_rules, is_auto_trim=is_auto_trim) 13 | self.register_rules(DEFAULT_RULES.DEFAULT_RULES) 14 | 15 | @staticmethod 16 | def register_default_rules(rules): 17 | for name, rule in rules.items(): 18 | DEFAULT_RULES.DEFAULT_RULES[name] = rule 19 | 20 | @staticmethod 21 | def register_aliased_default_rule(alias): 22 | BuildAliasedRule.BuildAliasedRule(DEFAULT_RULES.DEFAULT_RULES, alias) 23 | 24 | @staticmethod 25 | def set_default_auto_trim(is_auto_trim): 26 | IS_DEFAULT_AUTO_TRIM = bool(is_auto_trim) 27 | 28 | def register_aliased_rule(self, alias): 29 | BuildAliasedRule.BuildAliasedRule(self._validator_builders, alias) 30 | 31 | -------------------------------------------------------------------------------- /LIVR/Rules/Common.py: -------------------------------------------------------------------------------- 1 | try: 2 | import constants 3 | except ImportError: 4 | from . import constants 5 | 6 | 7 | class Required(object): 8 | def __init__(self, *args): 9 | pass 10 | 11 | def __call__(self, value, unuse, unuse_): 12 | if value == None or value == '': 13 | return 'REQUIRED' 14 | 15 | 16 | class NotEmpty(object): 17 | def __init__(self, *args): 18 | pass 19 | 20 | def __call__(self, value, unuse, unuse_): 21 | if value == '': 22 | return 'CANNOT_BE_EMPTY' 23 | 24 | 25 | class NotEmptyList(object): 26 | def __init__(self, *args): 27 | pass 28 | 29 | def __call__(self, lst, unuse, unuse_): 30 | if lst == None or lst == '': 31 | return 'CANNOT_BE_EMPTY' 32 | if not isinstance(lst, list): 33 | return 'FORMAT_ERROR' 34 | if not lst: 35 | return 'CANNOT_BE_EMPTY' 36 | 37 | 38 | class AnyObject(object): 39 | def __init__(self, *args): 40 | pass 41 | 42 | def __call__(self, lst, unuse, unuse_): 43 | if constants.EMPTY_PRIMITIVE(lst): 44 | return 45 | if not isinstance(lst, dict): 46 | return 'FORMAT_ERROR' 47 | -------------------------------------------------------------------------------- /LIVR/BuildAliasedRule.py: -------------------------------------------------------------------------------- 1 | try: 2 | import internal_reactor 3 | except ImportError: 4 | from . import internal_reactor 5 | 6 | class BuildAliasedRule(object): 7 | def __init__(self, source, alias): 8 | if not isinstance(alias, dict): 9 | raise Exception('Wrong alias format. Dict required') 10 | if not 'name' in alias: 11 | raise Exception('Alias name required') 12 | if not 'rules' in alias: 13 | raise Exception('Alias rules required') 14 | if 'error' in alias: 15 | self._error = alias['error'] 16 | else: 17 | self._error = None 18 | 19 | self._livr = {'value': alias['rules']} 20 | source[alias['name']] = self 21 | 22 | def __call__(self, *args): 23 | self.__rule_builders = args[0] 24 | self.__validator = internal_reactor.InternalValidator(self._livr) 25 | 26 | self.__validator.register_rules(self.__rule_builders) 27 | self.__validator.prepare() 28 | 29 | return self._validate 30 | 31 | def _validate(self, value, unuse, output): 32 | result = self.__validator.validate({'value': value}) 33 | 34 | if not result: 35 | return self._error or self.__validator.get_errors()['value'] 36 | 37 | output.append(result['value']) 38 | 39 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/positive/28-variable_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": ["required", "positive_integer"], 3 | "product1": ["required", { "variable_object": [ 4 | "product_type", { 5 | "material": { 6 | "product_type": "required", 7 | "material_id": ["required", "positive_integer"], 8 | "quantity": ["required", {"min_number": 1} ], 9 | "warehouse_id": "positive_integer" 10 | }, 11 | "service": { 12 | "product_type": "required", 13 | "name": ["required", {"max_length": 10} ] 14 | } 15 | } 16 | ]}], 17 | 18 | "product2": ["required", { "variable_object": [ 19 | "product_type", { 20 | "material": { 21 | "product_type": "required", 22 | "material_id": ["required", "positive_integer"], 23 | "quantity": ["required", {"min_number": 1} ], 24 | "warehouse_id": "positive_integer" 25 | }, 26 | "service": { 27 | "product_type": "required", 28 | "name": ["required", {"max_length": 10} ] 29 | } 30 | } 31 | ]}], 32 | 33 | "product3": ["required", { "variable_object": [ 34 | "product_type", { 35 | "material": { 36 | "product_type": "required", 37 | "material_id": ["required", "positive_integer"], 38 | "quantity": ["required", {"min_number": 1} ], 39 | "warehouse_id": "positive_integer" 40 | }, 41 | "service": { 42 | "product_type": "required", 43 | "name": ["required", {"max_length": 10} ] 44 | } 45 | } 46 | ]}] 47 | } -------------------------------------------------------------------------------- /LIVR/DEFAULT_RULES.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | PATH_TO_RULES = '/'.join(str(os.path.abspath(__file__)).split('/')[:-1])+'/Rules' 4 | sys.path.insert(0,PATH_TO_RULES) 5 | 6 | import Common 7 | import Modifiers 8 | import Special 9 | import String 10 | import Numeric 11 | import Meta 12 | 13 | 14 | DEFAULT_RULES = { 15 | 'required': Common.Required, 16 | 'not_empty': Common.NotEmpty, 17 | 'not_empty_list': Common.NotEmptyList, 18 | 'any_object': Common.AnyObject, 19 | 20 | 'one_of': String.OneOf, 21 | 'max_length': String.MaxLength, 22 | 'min_length': String.MinLength, 23 | 'length_equal': String.EqualLength, 24 | 'length_between': String.BetweenLength, 25 | 'length_between': String.BetweenLength, 26 | 'like': String.Like, 27 | 'eq': String.Eq, 28 | 'string': String.String, 29 | 30 | 'integer': Numeric.Integer, 31 | 'positive_integer': Numeric.PositiveInteger, 32 | 'decimal': Numeric.Decimal, 33 | 'positive_decimal': Numeric.PositiveDecimal, 34 | 'max_number': Numeric.MaxNumber, 35 | 'min_number': Numeric.MinNumber, 36 | 'number_between': Numeric.BetweenNumbers, 37 | 38 | 'email': Special.Email, 39 | 'equal_to_field': Special.EqualToField, 40 | 'url': Special.Url, 41 | 'iso_date': Special.IsoDate, 42 | 43 | 'nested_object': Meta.NestedObject, 44 | 'list_of': Meta.ListOf, 45 | 'list_of_objects': Meta.ListOfObjects, 46 | 'or': Meta.Or, 47 | 'variable_object': Meta.VariableObject, 48 | 'list_of_different_objects': Meta.ListOfDiferentObjects, 49 | 50 | 'default': Modifiers.Default, 51 | 'trim': Modifiers.Trim, 52 | 'to_lc': Modifiers.ToLc, 53 | 'to_uc': Modifiers.ToUc, 54 | 'remove': Modifiers.Remove, 55 | 'leave_only': Modifiers.LeaveOnly, 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /LIVR/Rules/Modifiers.py: -------------------------------------------------------------------------------- 1 | import re 2 | try: 3 | import constants 4 | except ImportError: 5 | from . import constants 6 | 7 | ESCAPE_RE = lambda string: string.replace('[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]', "\\$&") 8 | 9 | class Default(object): 10 | def __init__(self, *args): 11 | self._default = args[1] 12 | 13 | def __call__(self, value, unuse, output): 14 | if constants.EMPTY_PRIMITIVE(value): 15 | output.append(self._default) 16 | 17 | 18 | class Trim(object): 19 | def __init__(self, *args): 20 | pass 21 | 22 | def __call__(self, value, unuse, output): 23 | if value == None or value == '' or isinstance(value, constants.OBJECTS_LIST): 24 | return 25 | 26 | output.append(str(value).strip()) 27 | 28 | 29 | class ToLc(object): 30 | def __init__(self, *args): 31 | pass 32 | 33 | def __call__(self, value, unuse, output): 34 | if value == None or value == '' or isinstance(value, constants.OBJECTS_LIST): 35 | return 36 | output.append(str(value).lower()) 37 | 38 | 39 | class ToUc(object): 40 | def __init__(self, *args): 41 | pass 42 | 43 | def __call__(self, value, unuse, output): 44 | if value == None or value == '' or isinstance(value, constants.OBJECTS_LIST): 45 | return 46 | 47 | output.append(str(value).upper()) 48 | 49 | 50 | class Remove(object): 51 | def __init__(self, *args): 52 | self._chars = ESCAPE_RE(args[1]) 53 | 54 | def __call__(self, value, unuse, output): 55 | if value == None or value == '' or not isinstance(value, str): 56 | return 57 | 58 | output.append(re.sub('[{}]'.format(self._chars), '', value)) 59 | 60 | 61 | class LeaveOnly(object): 62 | def __init__(self, *args): 63 | self._chars = ESCAPE_RE(args[1]) 64 | 65 | def __call__(self, value, unuse, output): 66 | if value == None or value == '' or not isinstance(value, str): 67 | return 68 | 69 | output.append(re.sub('[^{}]'.format(self._chars), '', value)) 70 | -------------------------------------------------------------------------------- /LIVR/Rules/Special.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import datetime 5 | 6 | try: 7 | import constants 8 | except ImportError: 9 | from . import constants 10 | 11 | def basic_check(func): 12 | def dec(obj, value, unuse, output): 13 | if constants.EMPTY_PRIMITIVE(value): 14 | return 15 | if not isinstance(value, constants.PRIMITIVE_LIST): 16 | return 'FORMAT_ERROR' 17 | return func(obj, value, unuse, output) 18 | return dec 19 | 20 | 21 | class Email(object): 22 | _reg_exp_mail = r'^(?:[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])+$' 23 | def __init__(self, *args): 24 | pass 25 | 26 | @basic_check 27 | def __call__(self, email=None, unuse=None, unuse_=None): 28 | if not re.match(self._reg_exp_mail, str(email), re.IGNORECASE): 29 | return 'WRONG_EMAIL' 30 | if re.match(r'\@.*\@', str(email)): 31 | return 'WRONG_EMAIL' 32 | if re.match(r'\@.*_', str(email)): 33 | return 'WRONG_EMAIL' 34 | 35 | 36 | class EqualToField(object): 37 | def __init__(self, *args): 38 | self._field = args[1] 39 | 40 | @basic_check 41 | def __call__(self, value, params, unuse): 42 | if value != params[self._field]: 43 | return 'FIELDS_NOT_EQUAL' 44 | 45 | 46 | class Url(object): 47 | _url_re = re.compile( 48 | r'^(?:http|https)s?://' 49 | r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' 50 | r'localhost|' 51 | r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' 52 | r'(?::\d+)?' 53 | r'(?:/?|[/?]\S+)$', re.I) 54 | 55 | def __init__(self, *args): 56 | pass 57 | 58 | @basic_check 59 | def __call__(self, value, params, unuse): 60 | if len(value) < 2083 and self._url_re.match(value): 61 | return 62 | 63 | return 'WRONG_URL' 64 | 65 | 66 | class IsoDate(object): 67 | def __init__(self, *args): 68 | pass 69 | 70 | @basic_check 71 | def __call__(self, value, params, unuse): 72 | try: 73 | datetime.datetime.strptime(value, '%Y-%m-%d') 74 | except ValueError: 75 | return 'WRONG_DATE' 76 | -------------------------------------------------------------------------------- /LIVR/test/test_suite/negative/28-variable_object/rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "order_id": ["required", "positive_integer"], 3 | "product1": ["required", { "variable_object": [ 4 | "product_type", { 5 | "material": { 6 | "product_type": "required", 7 | "material_id": ["required", "positive_integer"], 8 | "quantity": ["required", {"min_number": 1} ], 9 | "warehouse_id": "positive_integer" 10 | }, 11 | "service": { 12 | "product_type": "required", 13 | "name": ["required", {"max_length": 10} ] 14 | } 15 | } 16 | ]}], 17 | 18 | "product2": ["required", { "variable_object": [ 19 | "product_type", { 20 | "material": { 21 | "product_type": "required", 22 | "material_id": ["required", "positive_integer"], 23 | "quantity": ["required", {"min_number": 1} ], 24 | "warehouse_id": "positive_integer" 25 | }, 26 | "service": { 27 | "product_type": "required", 28 | "name": ["required", {"max_length": 10} ] 29 | } 30 | } 31 | ]}], 32 | 33 | "product3": ["required", { "variable_object": [ 34 | "product_type", { 35 | "material": { 36 | "product_type": "required", 37 | "material_id": ["required", "positive_integer"], 38 | "quantity": ["required", {"min_number": 1} ], 39 | "warehouse_id": "positive_integer" 40 | }, 41 | "service": { 42 | "product_type": "required", 43 | "name": ["required", {"max_length": 10} ] 44 | } 45 | } 46 | ]}], 47 | 48 | "product4": ["required", { "variable_object": [ 49 | "product_type", { 50 | "material": { 51 | "product_type": "required", 52 | "material_id": ["required", "positive_integer"], 53 | "quantity": ["required", {"min_number": 1} ], 54 | "warehouse_id": "positive_integer" 55 | }, 56 | "service": { 57 | "product_type": "required", 58 | "name": ["required", {"max_length": 10} ] 59 | } 60 | } 61 | ]}], 62 | 63 | "product5": ["required", { "variable_object": [ 64 | "product_type", { 65 | "material": { 66 | "product_type": "required", 67 | "material_id": ["required", "positive_integer"], 68 | "quantity": ["required", {"min_number": 1} ], 69 | "warehouse_id": "positive_integer" 70 | }, 71 | "service": { 72 | "product_type": "required", 73 | "name": ["required", {"max_length": 10} ] 74 | } 75 | } 76 | ]}] 77 | } -------------------------------------------------------------------------------- /LIVR/Rules/Numeric.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | try: 5 | import constants 6 | except ImportError: 7 | from . import constants 8 | 9 | def basic_integer_check(func): 10 | def dec(obj, value, unuse, output): 11 | if constants.EMPTY_PRIMITIVE(value): 12 | return 13 | if not isinstance(value, constants.PRIMITIVE_LIST): 14 | return 'FORMAT_ERROR' 15 | return func(obj, value, unuse, output) 16 | return dec 17 | 18 | def formatize_numeric_value(value): 19 | if isinstance(value, str): 20 | try: 21 | return int(value) 22 | except ValueError: 23 | pass 24 | try: 25 | return float(value) 26 | except ValueError: 27 | pass 28 | return value 29 | 30 | 31 | class Integer(object): 32 | def __init__(self, *args): 33 | pass 34 | 35 | @basic_integer_check 36 | def __call__(self, value, unuse, output): 37 | if not re.match("^-?[0-9]+$", str(value)): 38 | return 'NOT_INTEGER' 39 | output.append(int(value)) 40 | 41 | class PositiveInteger(object): 42 | def __init__(self, *args): 43 | pass 44 | 45 | @basic_integer_check 46 | def __call__(self, value, unuse, output): 47 | if not re.match("^[1-9][0-9]*$", str(value)): 48 | return 'NOT_POSITIVE_INTEGER' 49 | output.append(int(value)) 50 | 51 | class Decimal(object): 52 | def __init__(self, *args): 53 | pass 54 | 55 | @basic_integer_check 56 | def __call__(self, value, unuse, output): 57 | if not re.match("^(?:\-?(?:[0-9]+\.[0-9]+)|(?:[0-9]+))$", str(value)): 58 | return 'NOT_DECIMAL' 59 | output.append(formatize_numeric_value(value)) 60 | 61 | class PositiveDecimal(object): 62 | def __init__(self, *args): 63 | pass 64 | 65 | @basic_integer_check 66 | def __call__(self, value, unuse, output): 67 | if not re.match("^(?:(?:[0-9]*\.[0-9]+)|(?:[1-9][0-9]*))$", str(value)): 68 | return 'NOT_POSITIVE_DECIMAL' 69 | output.append(formatize_numeric_value(value)) 70 | 71 | class MaxNumber(object): 72 | def __init__(self, *args): 73 | self._max_number = float(args[1]) 74 | 75 | @basic_integer_check 76 | def __call__(self, number, unuse, output): 77 | try: 78 | if float(number) > self._max_number: 79 | return 'TOO_HIGH' 80 | except: 81 | return "NOT_NUMBER" 82 | output.append(formatize_numeric_value(number)) 83 | 84 | class MinNumber(object): 85 | def __init__(self, *args): 86 | self._min_number = float(args[1]) 87 | 88 | @basic_integer_check 89 | def __call__(self, number, unuse, output): 90 | try: 91 | if float(number) < self._min_number: 92 | return 'TOO_LOW' 93 | except: 94 | return "NOT_NUMBER" 95 | output.append(formatize_numeric_value(number)) 96 | 97 | class BetweenNumbers(object): 98 | def __init__(self, *args): 99 | self._min_number = float(args[1]) 100 | self._max_number = float(args[2]) 101 | 102 | @basic_integer_check 103 | def __call__(self, number, unuse, output): 104 | try: 105 | if float(number) > self._max_number: 106 | return 'TOO_HIGH' 107 | if float(number) < self._min_number: 108 | return 'TOO_LOW' 109 | except: 110 | return "NOT_NUMBER" 111 | output.append(formatize_numeric_value(number)) 112 | -------------------------------------------------------------------------------- /LIVR/Rules/String.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import re 4 | 5 | try: 6 | import constants 7 | except ImportError: 8 | from . import constants 9 | 10 | def base_string_check(func): 11 | def dec(obj, value, unuse, output): 12 | if isinstance(value, (int, float)): 13 | value = str(value) 14 | if constants.EMPTY_PRIMITIVE(value): 15 | return 16 | if not isinstance(value, constants.PRIMITIVE_LIST): 17 | return 'FORMAT_ERROR' 18 | return func(obj, value, unuse, output) 19 | return dec 20 | 21 | 22 | class OneOf(object): 23 | def __init__(self, *args): 24 | self._allowed_list = args[1] 25 | 26 | if not isinstance(self._allowed_list, list): 27 | self._allowed_list = args[1:] 28 | 29 | @base_string_check 30 | def __call__(self, value, unuse, output): 31 | for val in self._allowed_list: 32 | if str(value) == str(val): 33 | output.append(val) 34 | return 35 | return 'NOT_ALLOWED_VALUE' 36 | 37 | class MaxLength(object): 38 | def __init__(self, *args): 39 | self._max_length = int(args[1]) 40 | # if self._max_length < 1: 41 | # raise Exception('Wrong standard value! Only positive value') 42 | 43 | @base_string_check 44 | def __call__(self, value, unuse, output): 45 | if len(value) > self._max_length: 46 | return 'TOO_LONG' 47 | output.append(value) 48 | 49 | class MinLength(object): 50 | def __init__(self, *args): 51 | self._min_length = args[1] 52 | 53 | @base_string_check 54 | def __call__(self, value, unuse, output): 55 | if len(value) < self._min_length: 56 | return 'TOO_SHORT' 57 | output.append(value) 58 | 59 | class EqualLength(object): 60 | def __init__(self, *args): 61 | self._length = args[1] 62 | 63 | @base_string_check 64 | def __call__(self, value, unuse, output): 65 | if len(value) > self._length: 66 | return 'TOO_LONG' 67 | if len(value) < self._length: 68 | return 'TOO_SHORT' 69 | output.append(value) 70 | 71 | class BetweenLength(object): 72 | def __init__(self, *args): 73 | self._min_length = args[1] 74 | self._max_length = args[2] 75 | # if self._max_length < 1: 76 | # raise Exception('Wrong standard value! Only positive value') 77 | 78 | @base_string_check 79 | def __call__(self, value, unuse, output): 80 | if len(value) > self._max_length: 81 | return 'TOO_LONG' 82 | if len(value) < self._min_length: 83 | return 'TOO_SHORT' 84 | output.append(value) 85 | 86 | class Like(object): 87 | def __init__(self, *args): 88 | self._sample = args[1] 89 | try: 90 | self._flag = str(args[2]).lower() 91 | except: 92 | self._flag = '' 93 | 94 | @base_string_check 95 | def __call__(self, value, unuse, output): 96 | if not re.match(self._sample, str(value), re.I if self._flag == 'i' else re.U): 97 | return 'WRONG_FORMAT' 98 | output.append(value) 99 | 100 | class Eq(object): 101 | def __init__(self, *args): 102 | self._allowed_value = args[1] 103 | 104 | @base_string_check 105 | def __call__(self, value, unuse, output): 106 | if str(self._allowed_value) == str(value): 107 | output.append(self._allowed_value) 108 | return 109 | return 'NOT_ALLOWED_VALUE' 110 | 111 | class String(object): 112 | def __init__(self, *args): 113 | pass 114 | 115 | @base_string_check 116 | def __call__(self, value, unuse, output): 117 | output.append(value) 118 | 119 | -------------------------------------------------------------------------------- /LIVR/internal_reactor.py: -------------------------------------------------------------------------------- 1 | 2 | class InternalValidator(object): 3 | def __init__(self, livr_rules, is_auto_trim = False): 4 | self._is_prepare = False 5 | self._livr_rules = livr_rules 6 | self._validators = {} 7 | self._validator_builders = {} 8 | self._errors = None 9 | self._is_auto_trim = is_auto_trim 10 | 11 | def _make_validators(self, rules): 12 | if isinstance(rules, dict): 13 | return [self._build_validator(**self._parse_rule({name:rule})) for name, rule in rules.items()] 14 | if isinstance(rules, list): 15 | return [self._build_validator(**self._parse_rule(rule)) for rule in rules] 16 | return [self._build_validator(**self._parse_rule(rules))] 17 | 18 | def prepare(self): 19 | if self._is_prepare: 20 | return 21 | for name, rules in self._livr_rules.items(): 22 | self._validators[name] = self._make_validators(rules) 23 | self._is_prepare = True 24 | 25 | def validate(self, data): 26 | errors = {} 27 | result = {} 28 | 29 | if not self._is_prepare: 30 | self.prepare() 31 | if self._is_auto_trim: 32 | self._auto_trim(data) 33 | if not isinstance(data, dict): 34 | self._error = "FORMAT_ERROR" 35 | return 36 | 37 | for field_name, validators in self._validators.items(): 38 | if not validators: 39 | continue 40 | mid_result = [] 41 | value = data[field_name] if field_name in data else None 42 | 43 | for func in validators: 44 | arg = result[field_name] if field_name in result else value 45 | error_code = func(arg, data, mid_result) 46 | 47 | if error_code: 48 | errors[field_name] = error_code 49 | break 50 | elif len(mid_result): 51 | result[field_name] = mid_result[-1] 52 | elif field_name in data and not field_name in result: 53 | result[field_name] = value 54 | 55 | if not errors: 56 | self._errors = None 57 | return result 58 | else: 59 | self._errors = errors 60 | return False 61 | 62 | def get_errors(self): 63 | return self._errors 64 | 65 | def get_rules(self): 66 | return self._validator_builders 67 | 68 | def register_rules(self, rules): 69 | for rule_name, rule_value in rules.items(): 70 | self._validator_builders[rule_name] = rule_value 71 | 72 | def _parse_rule(self, livr_rule): 73 | if isinstance(livr_rule, dict): 74 | name = list(livr_rule.keys())[0] 75 | content = livr_rule[name] 76 | 77 | if not isinstance(content, list): 78 | content = [content] 79 | else: 80 | name = livr_rule 81 | content = [] 82 | return {"name": name, "args": content} 83 | 84 | def _build_validator(self, name, args): 85 | if not name in self._validator_builders: 86 | raise Exception("Rule [{}] not registered".format(name)) 87 | return self._validator_builders[name](self._validator_builders, *args) 88 | 89 | def _auto_trim(self, data): 90 | if type(data) is str: 91 | return data.strip() 92 | 93 | elif type(data) is list: 94 | trimmed_list = [] 95 | 96 | for val in data: 97 | trimmed_list.append(self._auto_trim(val)) 98 | return trimmed_list 99 | 100 | elif type(data) is dict: 101 | trimmed_dict = {} 102 | 103 | for key in data: 104 | trimmed_dict[key] = self._auto_trim(data[key]) 105 | return trimmed_dict 106 | return data 107 | -------------------------------------------------------------------------------- /LIVR/test/case_handler.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sys 5 | PATH_TO_TESTS_INV = '/'.join(str(os.path.abspath(__file__)).split('/')[:-1]) 6 | PATH_TO_VALIDATOR = '/'.join(str(os.path.abspath(__file__)).split('/')[:-2]) 7 | sys.path.insert(0,PATH_TO_VALIDATOR) 8 | import Validator 9 | from livr_test import TestSuite 10 | 11 | def negative_test(data, current_test): 12 | if not 'rules' in data or not 'input' in data or not 'errors' in data: 13 | return 14 | validator = Validator.Validator(data['rules']) 15 | validator.validate(data['input']) 16 | 17 | """ If need to debug uncoment next code""" 18 | standard_errors = data['errors'] 19 | current_errors = validator.get_errors() 20 | if standard_errors == current_errors: 21 | print('Test \'{0}\' is Passed!!'.format(current_test)) 22 | else: 23 | print('Test \'{}\' is NOT passed \n Gives:\n\n{}\n\n Must give:\n\n{}\n\n'.format(current_test, 24 | current_errors, 25 | standard_errors)) 26 | 27 | return [data['errors'], validator.get_errors()] 28 | 29 | def positive_test(data, current_test): 30 | if not 'rules' in data or not 'input' in data or not 'output' in data: 31 | return 32 | validator = Validator.Validator(data['rules']) 33 | result = validator.validate(data['input']) 34 | 35 | """ If need to debug uncoment next code""" 36 | standart_output = data['output'] 37 | if result: 38 | if standart_output == result: 39 | print('Test \'{0}\' is Passed!!'.format(current_test)) 40 | else: 41 | print('Test \'{0}\' is NOT passed\nGives result:\n\n{1}\n\nMust give:\n\n{2}\n\n'.format(current_test, 42 | result, 43 | standart_output)) 44 | else: 45 | print('Test \'{0}\' is NOT passed\nGives errors:\n\n{1}\n\n Must give:\n\n{2}\n\n'.format(current_test, 46 | validator.get_errors(), 47 | standart_output)) 48 | return [data['output'], result] 49 | 50 | def aliase_negative_test(data, current_test): 51 | 52 | if not 'rules' in data or not 'input' in data or not 'errors' in data or not 'aliases' in data: 53 | return 54 | validator = Validator.Validator(data['rules']) 55 | 56 | for alias in data['aliases']: 57 | validator.register_aliased_rule(alias) 58 | validator.validate(data['input']) 59 | 60 | """ If need to debug uncoment next code""" 61 | standard_errors = data['errors'] 62 | current_errors = validator.get_errors() 63 | if standard_errors == current_errors: 64 | print('Test \'{0}\' is Passed!!'.format(current_test)) 65 | else: 66 | print('Test \'{0}\' is NOT passed \n Gives:\n\n{1}\n\n Must give:\n\n{2}\n\n'.format(current_test, 67 | current_errors, 68 | standard_errors)) 69 | 70 | return [data['errors'], validator.get_errors()] 71 | 72 | def aliase_positive_test(data, current_test): 73 | if not 'rules' in data or not 'input' in data or not 'output' in data or not 'aliases' in data: 74 | return 75 | validator = Validator.Validator(data['rules']) 76 | 77 | for alias in data['aliases']: 78 | validator.register_aliased_rule(alias) 79 | result = validator.validate(data['input']) 80 | 81 | """ If need to debug uncoment next code""" 82 | standart_output = data['output'] 83 | if result: 84 | if standart_output == result: 85 | print('Test \'{0}\' is Passed!!'.format(current_test)) 86 | else: 87 | print('Test \'{0}\' is NOT passed\nGives result:\n\n{1}\n\nMust give:\n\n{2}\n\n'.format(current_test, 88 | result, 89 | standart_output)) 90 | else: 91 | print('Test \'{0}\' is NOT passed\nGives errors:\n\n{1}\n\n Must give:\n\n{2}\n\n'.format(current_test, 92 | validator.get_errors(), 93 | standart_output)) 94 | 95 | return [data['output'], result] 96 | 97 | if __name__ == "__main__": 98 | test_engine = TestSuite() 99 | 100 | test_engine.runTest(PATH_TO_TESTS_INV + '/test_suite/positive', positive_test) 101 | test_engine.runTest(PATH_TO_TESTS_INV + '/test_suite/negative', negative_test) 102 | test_engine.runTest(PATH_TO_TESTS_INV + '/test_suite/aliases_negative', aliase_negative_test) 103 | test_engine.runTest(PATH_TO_TESTS_INV + '/test_suite/aliases_positive', aliase_positive_test) 104 | -------------------------------------------------------------------------------- /LIVR/Rules/Meta.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | ROOT_PATH = '/'.join(str(os.path.abspath(__file__)).split('/')[:-2]) 4 | sys.path.insert(0,ROOT_PATH) 5 | try: 6 | import constants 7 | import internal_reactor 8 | except ImportError: 9 | from . import constants 10 | from . import internal_reactor 11 | 12 | class NestedObject(object): 13 | def __init__(self, *args): 14 | _livr = args[1] 15 | _rule_builders = args[0] 16 | self._validator = internal_reactor.InternalValidator(_livr) 17 | 18 | self._validator.register_rules(_rule_builders) 19 | self._validator.prepare() 20 | 21 | def __call__(self, nested_obj, unuse, output): 22 | if not nested_obj or nested_obj == 0: 23 | return 24 | if not isinstance(nested_obj, dict): 25 | return 'FORMAT_ERROR' 26 | 27 | result = self._validator.validate(nested_obj) 28 | 29 | if not result: 30 | return self._validator.get_errors() 31 | 32 | output.append(result) 33 | 34 | class ListOf(object): 35 | def __init__(self, *args): 36 | _livr = args[1] 37 | _rule_builders = args[0] 38 | self._validator = internal_reactor.InternalValidator({'field':_livr}) 39 | 40 | self._validator.register_rules(_rule_builders) 41 | self._validator.prepare() 42 | 43 | def __call__(self, values, unuse, output): 44 | if not values or values == 0: 45 | return 46 | if not isinstance(values, dict) and not isinstance(values, list): 47 | return 'FORMAT_ERROR' 48 | return self._check_validation(values, output) 49 | 50 | def _check_validation(self, values, output): 51 | results = [] 52 | errors = [] 53 | error_flag = False 54 | 55 | for val in values: 56 | result = self._validator.validate({'field': val}) 57 | 58 | if result: 59 | results.append(result['field']) 60 | errors.append(None) 61 | else: 62 | error_flag = True 63 | errors.append(self._validator.get_errors()['field']) 64 | 65 | if error_flag: 66 | return errors 67 | 68 | output.append(results) 69 | 70 | class ListOfObjects(object): 71 | def __init__(self, *args): 72 | _livr = args[1] 73 | _rule_builders = args[0] 74 | self._validator = internal_reactor.InternalValidator(_livr) 75 | 76 | self._validator.register_rules(_rule_builders) 77 | self._validator.prepare() 78 | 79 | def __call__(self, objects, unuse, output): 80 | if objects == None or objects == '': 81 | return 82 | if not isinstance(objects, dict) and not isinstance(objects, list): 83 | return 'FORMAT_ERROR' 84 | 85 | return self._check_validation(objects, output) 86 | 87 | def _check_validation(self, objects, output): 88 | results = [] 89 | errors = [] 90 | error_flag = False 91 | 92 | for obj in objects: 93 | if not isinstance(obj, dict): 94 | errors.append('FORMAT_ERROR') 95 | continue 96 | 97 | result = self._validator.validate(obj) 98 | 99 | if result: 100 | results.append(result) 101 | errors.append(None) 102 | else: 103 | error_flag = True 104 | errors.append(self._validator.get_errors()) 105 | 106 | if error_flag: 107 | return errors 108 | 109 | output.append(results) 110 | 111 | class ListOfDiferentObjects(object): 112 | def __init__(self, *args): 113 | _rule_builders = args[0] 114 | _livrs = args[2] 115 | self._selector_fields = args[1] 116 | self._validators = {} 117 | 118 | for selector, livr in _livrs.items(): 119 | validator = internal_reactor.InternalValidator(livr) 120 | 121 | validator.register_rules(_rule_builders) 122 | validator.prepare() 123 | self._validators[selector] = validator 124 | 125 | def __call__(self, objects, unuse, output): 126 | results = [] 127 | errors = [] 128 | error_flag = False 129 | 130 | if not objects or objects == 0: 131 | return 132 | if not isinstance(objects, list): 133 | return 'FORMAT_ERROR' 134 | 135 | for obj in objects: 136 | if not isinstance(obj, dict) and not self._selector_fields in obj: 137 | errors.append("FORMAT_ERROR") 138 | continue 139 | if not obj[self._selector_fields] in self._validators: 140 | errors.append("FORMAT_ERROR") 141 | continue 142 | 143 | validator = self._validators[obj[self._selector_fields]] 144 | result = validator.validate(obj) 145 | 146 | if result: 147 | results.append(result) 148 | errors.append(None) 149 | else: 150 | error_flag = True 151 | errors.append(validator.get_errors()) 152 | 153 | if error_flag: 154 | return errors 155 | 156 | output.append(results) 157 | 158 | 159 | class Or(object): 160 | def __init__(self, *args): 161 | rule_builders = args[0] 162 | self._validators = [] 163 | self.rules = args[1:] 164 | for rule in args[1:]: 165 | validator = internal_reactor.InternalValidator({'field': rule}) 166 | 167 | validator.register_rules(rule_builders) 168 | validator.prepare() 169 | self._validators.append(validator) 170 | 171 | def __call__(self, value, unuse, output): 172 | last_error = None 173 | 174 | if constants.EMPTY_PRIMITIVE(value): 175 | return 176 | for validator in self._validators: 177 | result = validator.validate({'field': value}) 178 | 179 | if result: 180 | output.append(result['field']) 181 | return 182 | else: 183 | last_error = validator.get_errors()['field'] 184 | 185 | if last_error: 186 | return last_error 187 | 188 | 189 | class VariableObject(object): 190 | def __init__(self, *args): 191 | _rule_builders = args[0] 192 | _livrs = args[2] 193 | self._selector_fields = args[1] 194 | self._validators = {} 195 | 196 | for selector, livr in _livrs.items(): 197 | validator = internal_reactor.InternalValidator(livr) 198 | 199 | validator.register_rules(_rule_builders) 200 | validator.prepare() 201 | self._validators[selector] = validator 202 | 203 | def __call__(self, obj, unuse, output): 204 | if constants.EMPTY_PRIMITIVE(obj): 205 | return 206 | if not isinstance(obj, dict) and not self._selector_fields in obj: 207 | return "FORMAT_ERROR" 208 | if not obj[self._selector_fields] in self._validators: 209 | return "FORMAT_ERROR" 210 | 211 | validator = self._validators[obj[self._selector_fields]] 212 | result = validator.validate(obj) 213 | if result: 214 | output.append(result) 215 | return 216 | return validator.get_errors() 217 | 218 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | .. image:: https://travis-ci.org/asholok/python-validator-livr.svg 3 | :target: https://travis-ci.org/asholok/python-validator-livr 4 | 5 | ====== 6 | README 7 | ====== 8 | 9 | NAME 10 | ==== 11 | 12 | LIVR.Validator - Lightweight validator supporting Language Independent Validation Rules Specification (LIVR) 13 | 14 | Python 2 and 3 compatible 15 | 16 | SYNOPSIS 17 | ======== 18 | 19 | Common usage:: 20 | 21 | from LIVR import Validator 22 | Validator.Validator.set_default_auto_trim(True) 23 | 24 | validator = Validator.Validator({ 25 | 'name': 'required', 26 | 'email': [ 'required', 'email' ], 27 | 'gender': { 'one_of' : ['male', 'female'] }, 28 | 'phone': { 'max_length' : 10 }, 29 | 'password': [ 'required', {'min_length' : 10} ], 30 | 'password2': { 'equal_to_field' : 'password' } 31 | }) 32 | 33 | valid_data = validator.validate(user_data) 34 | 35 | if valid_data: 36 | save_user_data(valid_data) 37 | else: 38 | some_error_handler(validator.get_errors()) 39 | 40 | You can use filters separately or can combine them with validation:: 41 | 42 | validator = Validator.Validator({ 43 | 'email': [ 'required', 'trim', 'email', 'to_lc' ] 44 | }) 45 | 46 | 47 | 48 | Feel free to register your own rules:: 49 | 50 | validator = Validator.Validator({ 51 | 'password': ['required', 'strong_password'] 52 | }) 53 | 54 | class StrongPassword(object): 55 | def __init__(self, *args): 56 | pass 57 | 58 | def __call__(self, value, unuse, *args): 59 | value == None or value == '': 60 | return 61 | 62 | if len(value) < 6: 63 | return 'WEAK_PASSWORD' 64 | 65 | validator.register_rules({ 'strong_password': StrongPassword}) 66 | 67 | Also you can use aliases for some case, but you must ensure that in aliase dict present required kyes 'rules' and 'name':: 68 | 69 | validator = Validator.Validator({ 70 | 'password': ['required', 'strong_password'] 71 | }) 72 | 73 | validator.register_aliased_rule({ 74 | 'name': 'strong_password', 75 | 'rules': {'min_length' : 9}, 76 | 'error': 'WEAK_PASSWORD' 77 | }) 78 | 79 | DESCRIPTION 80 | =========== 81 | 82 | See http://livr-spec.org for detailed documentation and list of supported rules. 83 | 84 | 85 | Features: 86 | 87 | * Rules are declarative and language independent 88 | * Any number of rules for each field 89 | * Return together errors for all fields 90 | * Excludes all fields that do not have validation rules described 91 | * Has possibility to validatate complex hierarchical structures 92 | * Easy to describe and undersand rules 93 | * Returns understandable error codes(not error messages) 94 | * Easy to add own rules 95 | * Rules are be able to change results output ("trim", "nested_object", for example) 96 | * Multipurpose (user input validation, configs validation, contracts programming etc) 97 | 98 | INSTALL 99 | ======= 100 | Install LIVR from PyPI using PIP:: 101 | 102 | sudo pip install LIVR 103 | 104 | CLASS METHODS 105 | ============= 106 | 107 | Validator.Validator(livr, is_auto_trim) 108 | --------------------------------------- 109 | 110 | Contructor creates validator objects. 111 | livr - validations rules. Rules description is available here - https://github.com/koorchik/LIVR 112 | 113 | is_auto_trim - asks validator to trim all values before validation. Output will be also trimmed. 114 | if is_auto_trim is undefined(or None) than default_auto_trim value will be used. 115 | 116 | 117 | Validator.Validator.register_default_rules({"rule_name": rule_builder }) 118 | ---------------------------------------------------------------------- 119 | 120 | rule_builder - is a function reference which will be called for building single rule validator. 121 | :: 122 | 123 | class MyRule(object): 124 | def __init__(self, *args): 125 | rule_builders = args[0] 126 | # rule_builders - are rules from original validator 127 | # to allow you create new validator with all supported rules 128 | # validator = Validator(livr) 129 | # validator.register_rules(rule_builders) 130 | # validator.prepare() 131 | 132 | def __call__(self, value, all_values, output_array): 133 | if not_valid: 134 | return "SOME_ERROR_CODE" 135 | else: 136 | # some usefull code 137 | 138 | Validator.Validator.register_default_rules( {"my_rule": MyRule} ) 139 | 140 | Then you can use "my_rule" for validation:: 141 | 142 | { 143 | 'name1': 'my_rule', # Call without parameters 144 | 'name2': { 'my_rule': arg1 }, # Call with one parameter. 145 | 'name3': { 'my_rule': [arg1] }, # Call with one parameter. 146 | 'name4': { 'my_rule': [ arg1, arg2, arg3 ] } # Call with many parameters. 147 | } 148 | 149 | Here is "max_number" implementation:: 150 | 151 | class MaxNumber(object): 152 | def __init__(self, *args): 153 | self._max_number = float(args[1]) 154 | 155 | def __call__(self, number, unuse, unuse_): 156 | # We do not validate empty fields. We have "required" rule for this purpose 157 | if number == None or number == '': 158 | return 159 | 160 | #return error message 161 | if float(number) > self._max_number: 162 | return 'TOO_HIGH' 163 | 164 | Validator.Validator.register_default_rules({ "max_number": MaxNumber }) 165 | 166 | All rules for the validator are equal. It does not distinguish "required", "list_of_different_objects" and "trim" rules. So, you can extend validator with any rules you like. 167 | 168 | Validator.Validator.get_default_rules() 169 | --------------------------------------- 170 | returns object containing all default rule_builders for the validator. You can register new rule or update existing one with "register_rules" method. 171 | 172 | Validator.Validator.set_default_auto_trim(is_auto_trim) 173 | ------------------------------------------------------- 174 | Enables or disables automatic trim for input data. If is on then every new validator instance will have auto trim option enabled 175 | 176 | 177 | OBJECT METHODS 178 | ============== 179 | 180 | 181 | validator.validate(input) 182 | ------------------------- 183 | Validates user input. On success returns valid_data (contains only data that has described validation rules). On error return false. 184 | :: 185 | 186 | valida_data = validator.validate(input) 187 | 188 | if valida_data: 189 | #use valida_data 190 | else: 191 | errors = validator.get_errors() 192 | 193 | 194 | validator.get_errors() 195 | ---------------------- 196 | Returns errors object. 197 | :: 198 | 199 | { 200 | "field1": "ERROR_CODE", 201 | "field2": "ERROR_CODE", 202 | ... 203 | } 204 | 205 | For example:: 206 | 207 | { 208 | "country": "NOT_ALLOWED_VALUE", 209 | "zip": "NOT_POSITIVE_INTEGER", 210 | "street": "REQUIRED", 211 | "building": "NOT_POSITIVE_INTEGER" 212 | } 213 | 214 | 215 | validator.register_rules({"rule_name": rule_builder}) 216 | ----------------------------------------------------- 217 | 218 | rule_builder - is a function reference which will be called for building single rule validator. 219 | 220 | See "Validator.Validator.register_default_rules" for rules examples. 221 | 222 | 223 | validator.get_rules() 224 | --------------------- 225 | 226 | returns object containing all rule_builders for the validator. You can register new rule or update existing one with "register_rules" method. 227 | 228 | 229 | validator.register_aliased_rule(alias) 230 | -------------------------------------- 231 | 232 | alias - is a composite validation rule. 233 | 234 | See "Validator.Validator.register_aliased_rule" for rules examples. 235 | 236 | AUTHOR 237 | ====== 238 | koorchik (Viktor Turskyi), asholok (Ihor Kolosha) 239 | 240 | BUGS 241 | ==== 242 | Please report any bugs or feature requests to Github https://github.com/asholok/python-validator-livr 243 | 244 | LICENSE AND COPYRIGHT 245 | ===================== 246 | 247 | Copyright 2012 Viktor Turskyi. 248 | 249 | This program is free software, you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: 250 | 251 | http://www.perlfoundation.org/artistic_license_2_0 252 | 253 | Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. 254 | 255 | If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. 256 | 257 | This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. 258 | 259 | This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. 260 | 261 | Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /LIVR.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: LIVR 3 | Version: 2.0.1 4 | Summary: LIVR validator. 5 | Home-page: https://github.com/asholok/python-validator-livr 6 | Author: Ihor Kolosha, Viktor Turstkiy 7 | Author-email: UNKNOWN 8 | License: look into README 9 | Description: 10 | .. image:: https://travis-ci.org/asholok/python-validator-livr.svg 11 | :target: https://travis-ci.org/asholok/python-validator-livr 12 | 13 | ====== 14 | README 15 | ====== 16 | 17 | NAME 18 | ==== 19 | 20 | LIVR.Validator - Lightweight validator supporting Language Independent Validation Rules Specification (LIVR) 21 | 22 | Python 2 and 3 compatible 23 | 24 | SYNOPSIS 25 | ======== 26 | 27 | Common usage:: 28 | 29 | from LIVR import Validator 30 | Validator.Validator.set_default_auto_trim(True) 31 | 32 | validator = Validator.Validator({ 33 | 'name': 'required', 34 | 'email': [ 'required', 'email' ], 35 | 'gender': { 'one_of' : ['male', 'female'] }, 36 | 'phone': { 'max_length' : 10 }, 37 | 'password': [ 'required', {'min_length' : 10} ], 38 | 'password2': { 'equal_to_field' : 'password' } 39 | }) 40 | 41 | valid_data = validator.validate(user_data) 42 | 43 | if valid_data: 44 | save_user_data(valid_data) 45 | else: 46 | some_error_hendler(validator.get_errors()) 47 | 48 | You can use filters separately or can combine them with validation:: 49 | 50 | validator = Validator.Validator({ 51 | 'email': [ 'required', 'trim', 'email', 'to_lc' ] 52 | }) 53 | 54 | 55 | 56 | Feel free to register your own rules:: 57 | 58 | validator = Validator.Validator({ 59 | 'password': ['required', 'strong_password'] 60 | }) 61 | 62 | class StrongPassword(object): 63 | def __init__(self, *args): 64 | pass 65 | 66 | def __call__(self, value, unuse, unuse): 67 | value == None or value == '': 68 | return 69 | 70 | if len(value) < 6: 71 | return 'WEAK_PASSWORD' 72 | 73 | validator.registerRules({ 'strong_password': StrongPassword}) 74 | 75 | Also you can use aliases for some case, but you must ensure that in aliase dict present required kyes 'rules' and 'name':: 76 | 77 | validator = Validator.Validator({ 78 | 'password': ['required', 'strong_password'] 79 | }) 80 | 81 | validator.register_aliased_rule({ 82 | 'name': 'strong_password', 83 | 'rules': {'min_length' : 9}, 84 | 'error': 'WEAK_PASSWORD' 85 | }) 86 | 87 | DESCRIPTION 88 | =========== 89 | 90 | See http://livr-spec.org for detailed documentation and list of supported rules. 91 | 92 | 93 | Features: 94 | 95 | * Rules are declarative and language independent 96 | * Any number of rules for each field 97 | * Return together errors for all fields 98 | * Excludes all fields that do not have validation rules described 99 | * Has possibility to validatate complex hierarchical structures 100 | * Easy to describe and undersand rules 101 | * Returns understandable error codes(not error messages) 102 | * Easy to add own rules 103 | * Rules are be able to change results output ("trim", "nested_object", for example) 104 | * Multipurpose (user input validation, configs validation, contracts programming etc) 105 | 106 | INSTALL 107 | ======= 108 | Install LIVR from PyPI using PIP:: 109 | 110 | sudo pip install LIVR 111 | 112 | CLASS METHODS 113 | ============= 114 | 115 | Validator.Validator(livr, is_auto_trim) 116 | --------------------------------------- 117 | 118 | Contructor creates validator objects. 119 | livr - validations rules. Rules description is available here - https://github.com/koorchik/LIVR 120 | 121 | is_auto_trim - asks validator to trim all values before validation. Output will be also trimmed. 122 | if is_auto_trim is undefined(or None) than default_auto_trim value will be used. 123 | 124 | 125 | Validator.Validator.registerDefaultRules({"rule_name": rule_builder }) 126 | ---------------------------------------------------------------------- 127 | 128 | rule_builder - is a function reference which will be called for building single rule validator. 129 | :: 130 | 131 | class MyRule(object): 132 | def __init__(self, *args): 133 | rule_builders = args[0] 134 | # rule_builders - are rules from original validator 135 | # to allow you create new validator with all supported rules 136 | # validator = Validator(livr) 137 | # validator.register_rules(rule_builders) 138 | # validator.prepare() 139 | 140 | def __call__(self, value, all_values, output_array): 141 | if not_valid: 142 | return "SOME_ERROR_CODE" 143 | else: 144 | # some usefull code 145 | 146 | Validator.Validator.register_default_rules( {"my_rule": MyRule} ) 147 | 148 | Then you can use "my_rule" for validation:: 149 | 150 | { 151 | 'name1': 'my_rule', # Call without parameters 152 | 'name2': { 'my_rule': arg1 }, # Call with one parameter. 153 | 'name3': { 'my_rule': [arg1] }, # Call with one parameter. 154 | 'name4': { 'my_rule': [ arg1, arg2, arg3 ] } # Call with many parameters. 155 | } 156 | 157 | Here is "max_number" implemenation:: 158 | 159 | class MaxNumber(object): 160 | def __init__(self, *args): 161 | self._max_number = float(args[1]) 162 | 163 | def __call__(self, number, unuse, unuse_): 164 | # We do not validate empty fields. We have "required" rule for this purpose 165 | if number == None or number == '': 166 | return 167 | 168 | #return error message 169 | if float(number) > self._max_number: 170 | return 'TOO_HIGH' 171 | 172 | Validator.Validator.register_default_rules({ "max_number": MaxNumber }) 173 | 174 | All rules for the validator are equal. It does not distinguish "required", "list_of_different_objects" and "trim" rules. So, you can extend validator with any rules you like. 175 | 176 | Validator.Validator.get_default_rules() 177 | --------------------------------------- 178 | returns object containing all default rule_builders for the validator. You can register new rule or update existing one with "register_rules" method. 179 | 180 | Validator.Validator.set_default_auto_trim(is_auto_trim) 181 | ------------------------------------------------------- 182 | Enables or disables automatic trim for input data. If is on then every new validator instance will have auto trim option enabled 183 | 184 | 185 | OBJECT METHODS 186 | ============== 187 | 188 | 189 | validator.validate(input) 190 | ------------------------- 191 | Validates user input. On success returns valid_data (contains only data that has described validation rules). On error return false. 192 | :: 193 | 194 | valida_data = validator.validate(input) 195 | 196 | if valida_data: 197 | #use valida_data 198 | else: 199 | errors = validator.get_errors() 200 | 201 | 202 | validator.get_errors() 203 | ---------------------- 204 | Returns errors object. 205 | :: 206 | 207 | { 208 | "field1": "ERROR_CODE", 209 | "field2": "ERROR_CODE", 210 | ... 211 | } 212 | 213 | For example:: 214 | 215 | { 216 | "country": "NOT_ALLOWED_VALUE", 217 | "zip": "NOT_POSITIVE_INTEGER", 218 | "street": "REQUIRED", 219 | "building": "NOT_POSITIVE_INTEGER" 220 | } 221 | 222 | 223 | validator.register_rules({"rule_name": rule_builder}) 224 | ----------------------------------------------------- 225 | 226 | rule_builder - is a function reference which will be called for building single rule validator. 227 | 228 | See "Validator.Validator.register_default_rules" for rules examples. 229 | 230 | 231 | validator.get_rules() 232 | --------------------- 233 | 234 | returns object containing all rule_builders for the validator. You can register new rule or update existing one with "register_rules" method. 235 | 236 | 237 | validator.register_aliased_rule(alias) 238 | -------------------------------------- 239 | 240 | alias - is a composite validation rule. 241 | 242 | See "Validator.Validator.register_aliased_rule" for rules examples. 243 | 244 | AUTHOR 245 | ====== 246 | koorchik (Viktor Turskyi), asholok (Ihor Kolosha) 247 | 248 | BUGS 249 | ==== 250 | Please report any bugs or feature requests to Github https://github.com/asholok/python-validator-livr 251 | 252 | LICENSE AND COPYRIGHT 253 | ===================== 254 | 255 | Copyright 2012 Viktor Turskyi. 256 | 257 | This program is free software, you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at: 258 | 259 | http://www.perlfoundation.org/artistic_license_2_0 260 | 261 | Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. 262 | 263 | If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. 264 | 265 | This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. 266 | 267 | This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. 268 | 269 | Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 270 | Platform: UNKNOWN 271 | --------------------------------------------------------------------------------