How to validate structure (or schema) of dictionary in Python? How to validate structure (or schema) of dictionary in Python? python python

How to validate structure (or schema) of dictionary in Python?


You may use schema (PyPi Link)

schema is a library for validating Python data structures, such as those obtained from config-files, forms, external services or command-line parsing, converted from JSON/YAML (or something else) to Python data-types.

from schema import Schema, And, Use, Optional, SchemaErrordef check(conf_schema, conf):    try:        conf_schema.validate(conf)        return True    except SchemaError:        return Falseconf_schema = Schema({    'version': And(Use(int)),    'info': {        'conf_one': And(Use(float)),        'conf_two': And(Use(str)),        'conf_three': And(Use(bool)),        Optional('optional_conf'): And(Use(str))    }})conf = {    'version': 1,    'info': {        'conf_one': 2.5,        'conf_two': 'foo',        'conf_three': False,        'optional_conf': 'bar'    }}print(check(conf_schema, conf))


Without using libraries, you could also define a simple recursive function like this:

def check_structure(struct, conf):    if isinstance(struct, dict) and isinstance(conf, dict):        # struct is a dict of types or other dicts        return all(k in conf and check_structure(struct[k], conf[k]) for k in struct)    if isinstance(struct, list) and isinstance(conf, list):        # struct is list in the form [type or dict]        return all(check_structure(struct[0], c) for c in conf)    elif isinstance(struct, type):        # struct is the type of conf        return isinstance(conf, struct)    else:        # struct is neither a dict, nor list, not type        return False

This assumes that the config can have keys that are not in your structure, as in your example.


Update: New version also supports lists, e.g. like 'foo': [{'bar': int}]


You can build structure using recursion:

def get_type(value):    if isinstance(value, dict):        return {key: get_type(value[key]) for key in value}    else:        return str(type(value))

And then compare required structure with your dictionary:

get_type(current_conf) == get_type(required_conf)

Example:

required_conf = {    'version': 1,    'info': {        'conf_one': 2.5,        'conf_two': 'foo',        'conf_three': False,        'optional_conf': 'bar'    }}get_type(required_conf){'info': {'conf_two': "<type 'str'>", 'conf_one': "<type 'float'>", 'optional_conf': "<type 'str'>", 'conf_three': "<type 'bool'>"}, 'version': "<type 'int'>"}