Data schema to validate parameters easily, quickly and with minimal code
Project description
dataskema
Data schema validation for python
- Validate types, formats, sizings, lines, etc. of incoming parameters
- Customizable types for own aplications
- Customizable validation messages
- Multi-language support
- Easy to use, minimum code using decorators
How to use dataskema
-
Define your own data schema using
dataskemadefault data types (mydatatypes.py) or using your own data types:from dataskema.data_types import DataTypes
class MyDataTypes(DataTypes):
address = DataTypes.type(DataTypes.title, { 'label': 'Address', 'regexp': '^[a-zA-Z0-9\\.\\@\\+\\-\\_]+$', }) phone_number = { 'type': 'str', 'max-size: 20, 'regexp': '^[0-9\\-]+]+$', } ... -
Import your data schema and use it with
dataskemavalidation decorators. Look that t.name is inherited from default data types of DataTypes class.import dataskeme from mydatatypes import MyDataTypes as t
@dataskeme.args(name=t.name, address=t.address, phone_number=t.phone_number) def print_contact_data(name: str, address: str, phone_numer: str): print(f"Name: {name}" print(f"Address: {address}" print(f"Phone number: {phone_number}"
def service_edit_contact(): name = 'Lorenzo' addresss = 'C/ Costa Rica, 32' phone_number = '999-845-321' try: print_contact_data(name, address, phone_number) except SchemaValidationResult as res: print(res.get_message())
-
In the above example, before printing contact data, it is validated with own data schema. The data are correct and no errors will be shown. But if we modify
mydatatypes.pyto force a validation error, then:phone_number = { 'type': 'str', 'max-size: 20, 'regexp': '^[0-9]+$', }) ...
The error will be:
'phone_number' has an invalid format
-
We can specify label for this paramente to show a better message:
phone_number = { 'type': 'str', 'label': 'Phone number', 'max-size: 20, 'regexp': '^[0-9]+$', }) ...
The error will be:
'Phone number' has an invalid format
-
We can specify our own format error message too:
phone_number = { 'type': 'str', 'label': 'Phone number', 'max-size: 20, 'regexp': '^[0-9]+$', 'message': '{name} has an invalid phone number format' }) ...
The error will be:
'Phone number' has an invalid phone number format
5Other test: Empty name value and change name type as mandatory using inline type change. Look t.mandatory method in the decorator:
@dataskeme.args(name=t.mandatory(t.name), address=t.address, phone_number=t.phone_number)
def print_contact_data(name: str, address: str, phone_numer: str):
...
The error will be:
'name' is mandatory
...and 1 error more
-
Want you see all errors? Change
dataskeme.MAX_VALIDATION_MESSAGES = 10to see the 10 first validation messages odataskeme.MAX_VALIDATION_MESSAGES = 0to see all'name' is mandatory 'Phone number' has an invalid phone number format
-
Now, 'name' is a field name it is not a known name. Then, use t.label() to assign a new label o modify your data scheme to assign a label to this type.
@dataskeme.args(name=t.label(t.mandatory(t.name), 'Contact name'), address=t.address, phone_number=t.phone_number) def print_contact_data(name: str, address: str, phone_numer: str): ...
or create data type directly in your data schema:
name = DataTypes.type(DataTypes.name, {
'label': 'Contact name',
'required': True,
})
...
@dataskeme.args(name=t.name, 'Contact name'), address=t.address, phone_number=t.phone_number)
def print_contact_data(name: str, address: str, phone_numer: str):
...
-
The error:
'Contact name' is mandatory 'Phone number' has an invalid phone number format
-
"Well, but I want to show errors in each field. Is this possible?" Yes, it is. Validation exception (
SchemaValidationResult) has a method to return validation info by field:get_result_of(field_name). This method returns this data structure:{ 'valid': 'message': 'label': }
The method get_results() returns all validation results in a dict whose keys are the field names. The method get_message() returns all validation messages. In own example, the returning would be:
get_results():
{
'name': {
'valid': False,
'message': 'It is mandatory',
'label': 'Contact name'
},
'address': {
'valid': True
},
'phone_number': {
'valid': False,
'message': 'It has an invalid phone number format',
'label': 'Phone number'
},
}
get_message():
"'Contact name' is mandator\n'Phone number' has an invalid phone number format",
-
dataskemasupports Spanish and English messages. Usedataskema.lang.DEFAULT = dataskema.lang.ESto show Spanish language. -
"Fine, but solution that I search is for Flask endpoints and its incoming parameters". No problem,
dataskemais the solution. For example, look that Flask endpoint. Look thatuser_idparameter passed asargumentfor the next method.@flask_app.route('/api/user/<user_id>', methods=['PUT']) def update_user(user_id: str): json_data = request.get_json() ...
-
This example not validate
user_idneitherjson_data. Now, we will use our decorators and our data schema (mydatatypes.py). Look asupdate_usermethod includes the json params that we need us. This params are defined by above decoratorflask_json. If the incoming params not validate then aSchemaValidationResultwill be raised. Look howuser_idis validated withargdecorator.@flask_app.route('/api/user/<user_id>', methods=['PUT']) @dataskema.args(user_id=t.user_id) @dataskema.flask_json(name=t.name, address.t.address, phone_number=t.phone_number) def update_user(user_id: str, name: str, address: str, phone_number: str): ...
-
"But, What happes if my GET method not contains JSON data because the data is in the query string?" Easy. Use
flask_querydecorator in the same way.@flask_app.route('/api/user/<user_id>', methods=['GET']) @dataskema.args(user_id=t.user_id) @dataskema.flask_query(name=t.name, address.t.address, phone_number=t.phone_number) def update_user(user_id: str, name: str, address: str, phone_number: str): ...
-
"And now, how catch the decorator exception to process validation result?" Use your own decorator (for example,
@my_json_result) to catch this result and response with JSON data as this example is shown:@flask_app.route('/api/user/<user_id>', methods=['PUT']) @my_json_result() @dataskema.args(user_id=t.user_id) @dataskema.flask_json(name=t.name, address.t.address, phone_number=t.phone_number) def update_user(user_id: str, name: str, address: str, phone_number: str): ...
The code of @my_json_result could be something as this:
def my_json_result():
def inner_function(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
try:
return function(*args, **kwargs)
except SchemaValidationResult as ve:
return {
'result': 'ERR',
'reason': ve.get_message(),
'errors': ve.get_results()
}
return wrapper
return inner_function
-
"All of this is bored for me. I hate decorators". Well, if you want to use the code for validate parameters in the traditional way, look this examples:
@flask_app.route('/api/user/<user_id>', methods=['PUT']) def update_user(user_id: str): try: args_validator = Args() args_validator.validate(user_id=t.user_id) json_validator = JSON() json_validator.validate(name=t.name, address.t.address, phone_number=t.phone_number) return {result: 'OK'} raise SchemaValidatorResult as ex: error_msg = ex.get_message() errors = ex.get_result() return {result: 'ERR', reason: error_msg, errors: errors}
Data types definition
-
'type': type of data:'int','float','str','bool','list','dict','any'. It would be a type that could be casting to python type without raise an exception. -
mandatory: the data must be mandatory
For 'type': 'str'
-
'white-list': [...] list of valid values for the data -
'icase': ignore case for matching thewhite-list
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file dataskema-0.4.tar.gz.
File metadata
- Download URL: dataskema-0.4.tar.gz
- Upload date:
- Size: 13.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.0 CPython/3.8.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3fed2d34e63587660498f42510c53a79d91b0399984d093fa0b256aacb61318
|
|
| MD5 |
092f951d9f7fb2e4bd91d9243443802c
|
|
| BLAKE2b-256 |
6f54f61eb0664fe07b07968a4eaaee97a450680d33ff8d9a203011aa1f4a7bb7
|