Home > Blockchain >  Access and validate json data using python
Access and validate json data using python

Time:09-07

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.

  • Related