I have following data and want to validate values of it either integer
, float
or string
I copied the validation code here and did some modifications on it to reach to expected output that I need. how to write validator method to validate the json element data with python
There are two problems that I'm having trouble solving
1. Validation of `points`
2. Accessing/validating `top_properties` keys to validate their values.
I tried to look around but could not come with proper solution to this Python Json Access Data
Parsing nested json data using Python
I'm sure I'm missing some points somewhere but I could not figure it out where :)
import json
import typing
import itertools
json_data = """{
"id": null,
"name": "12",
"cake_name": "test",
"metric": "1.2",
"anticipations": [
{
"time": "2018-01-01 00:00:00",
"points": 1,
"top_properties": {
"LA:TB2341": 0.23,
"LA:TB2342": 0.23,
"LA:TB2343": 0.23
},
"status": 0,
"alert": false
},
{
"time": "2018-01-02 00:00:00",
"points": 1,
"top_properties": {
"LA:TB2342": "0.23",
"LA:TB2341": 0.23,
"LA:TB2344": 0.23
},
"status": null,
"alert": true
}
]
}
"""
def validate(my_dict: typing.Dict, string_attributes, int_attributes, float_attributes):
validations_errors = []
# print(my_dict)
for (string,integer) in itertools.zip_longest(string_attributes, int_attributes):
if (string or integer) in my_dict: #there might be problem here;)
print("attribute:::",string, integer)
if string in string_attributes and not isinstance(my_dict.get(string), str):
validations_errors.append(f"key '{string}' is not a string, got {my_dict.get(string)}")
if integer in int_attributes and not isinstance(my_dict.get(integer), int):
# append to the list of errors
#print('attribute::', integer, isinstance(my_dict.get(integer), int))
validations_errors.append(f"key '{integer}' is not a integer, got {my_dict.get(integer)}")
return validations_errors
def custom_validator(json_data: typing.Dict):
string_attributes = ["id", "name", "cake_name", "time", "LA:TB2342"]
int_attributes = ['metric','points']
float_attributes = [...]
# now do it for anticipations
validation_errors = validate(json_data, string_attributes, int_attributes, float_attributes)
#print(validation_errors)
for i, anticipation in enumerate(json_data.get('anticipations')):
validation_error = validate(anticipation, string_attributes, int_attributes, float_attributes)
if validation_error:
validation_errors.append(f"anticipation -> {i} error: {validation_error}")
return validation_errors
data = json.loads(json_data)
print(custom_validator(data))
which yields
attribute::: id metric
attribute::: name points
attribute::: cake_name None
attribute::: time None
attribute::: time None
["key 'id' is not a string, got None", "key 'metric' is not a integer, got <class 'str'>", "key 'points' is not a integer, got <class 'NoneType'>"]
CodePudding user response:
My solution is a recursive soltuion, to read nested json data.
from functools import partial
from typing import Union, Callable
import json
def get_output(key, val, string_keys: list, int_keys: list, float_keys: list):
out = None
if key in string_keys:
if not isinstance(val, str):
out = f"key '{key}' is not a string, got {type(val)}"
elif key in int_keys:
if not isinstance(val, int):
out = f"key '{key}' is not a integer, got {type(val)}"
elif key in float_keys:
if not isinstance(val, float):
out = f"key '{key}' is not a float, got {type(val)}"
return out
def explore_json(json: Union[dict, list], validator: Callable, result=None):
if result is None:
result = []
if isinstance(json, dict):
for key, val in json.items():
if isinstance(val, (dict, list)):
result = explore_json(val, validator, result)
else:
out = validator(key, val)
if out is not None:
result.append(out)
elif isinstance(json, list):
for val in json:
result = explore_json(val, validator, result)
return result
validator = partial(get_output,
string_keys=["id", "name", "cake_name", "time"],
int_keys=['metric','points'],
float_keys=["LA:TB2342", "LA:TB2341", "LA:TB2344"])
data = json.loads(json_data)
explore_json(data, validator)
The output of this is:
["key 'id' is not a string, got <class 'NoneType'>",
"key 'metric' is not a integer, got <class 'str'>",
"key 'LA:TB2342' is not a float, got <class 'str'>"]
The advance of the partial function is that we can have a validator for each specific json.
Moreover, note that only the keys inside the list string_keys, int_keys, float_keys
defined in our specific validator can be in the output list any key not inside these lists is not verified.
Finally, I'm not sure if the lists are the same as yours, but just change them and check the output.