Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Built in solution for validating an dictionary [closed]

I'm using the following code to validate a dictionary (a) against another dictionary (check_against). Unfortunately my code isn't very readable so I was wondering if there is a faster/cleaner built in solution to achieve the same results. Maybe I just haven't googled the right keywords but I haven't found any discussion on what I would consider to be a fairly common task.

check_against = {
    'a' : str,
    'b' : {
        'c': int,
        'd': int,
    }
}

a = {
   'a' : 1,
   'c' : 1
}

def get_type_at_path(obj, chain):
    _key = chain.pop(0)
    if _key in obj:
        return key_exists(obj[_key], chain) if chain else type(obj[_key])

def root_to_leaf_paths(tree, cur=()):
    if isinstance(tree,dict):
        for n, s in tree.items():
            for path in root_to_leaf_paths(s, cur+(n,)):
                yield path
    else:
        yield [cur,tree]

for path,value_type in root_to_leaf_paths(check_against):
    a_value_type = get_type_at_path(a,list(path))
    if a_value_type == None:
        print(f"Missing key at path \"{list(path)}\"")
    elif not a_value_type == value_type:
        print(f"Value at path \"{list(path)}\" should be of type \"{value_type}\" but got {a_value_type}")

outputs

Value at path "['a']" should be of type "<class 'str'>" but got <class 'int'>
Missing key at path "['b', 'c']"
Missing key at path "['b', 'd']"
like image 299
TheAschr Avatar asked Sep 01 '26 03:09

TheAschr


1 Answers

You can adjust your root_to_leaf_paths() function a bit to treat it as a general dict flattener. Flatten both the schema and the data. Then the comparison is trivial.

schema = {
    'a' : str,
    'b' : {
        'c': int,
        'd': int,
    }
}

data = {
   'a' : 1,
   'c' : 1
}

def flatten(obj, path = tuple()):
    if isinstance(obj, dict):
        for k, v in obj.items():
            yield from flatten(v, path + (k,))
    else:
        yield (path, obj)

fschema = dict(flatten(schema))
fdata = dict(flatten(data))

for path, exp in fschema.items():
    if path in fdata:
        got = type(fdata[path])
        if got is not exp:
            print(f'Incorrect type: path={path} got={got} exp={exp}')
    else:
        print(f'Missing key: path={path}')
like image 145
FMc Avatar answered Sep 02 '26 17:09

FMc



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!