Sreeram TP
Sreeram TP

Reputation: 11917

Validate a input dict schema

I have a schema for a input dict in Python that goes like this,

SCHEMA = {
    'mode': ('mode_1', 'mode_2', 'mode_3'),
    'method': ('method_1', 'method_2'),
    'other': {
        'x1': [1, 365],
        'x2': [0., 1.0]
    }

}

I want to validate the given input dict,

inp = {
    'mode': 'mode_1',
    'method': 'method_1',
    'other': {
        'x1': 1,
        'x2': 1.0
    }

}
  1. Contains the same keys
  2. If any of the value is a dict check that dict too have same keys
  3. Check the values of input dict are in the schema range. For example, for the key 'mode' the input dict should have value from ('mode_1', 'mode_2', 'mode_3'). Like wise for all the key-value pair.
  4. If the type of a value in SCHEMA is a list, I also want to check the corresponding value from the input dict is greater than value[0] and less than value[1]

I can think about doing it with loops. But can't think of a generalized way to do it. If I just looped over the two dicts and compared the values, I have to rewrite the logic if the schema changes.

Is there any straight forward way to validate the schema?

Upvotes: 2

Views: 2651

Answers (3)

Ajax1234
Ajax1234

Reputation: 71451

You can use recursion:

SCHEMA = {'mode': ('mode_1', 'mode_2', 'mode_3'), 'method': ('method_1', 'method_2'), 'other': {'x1': [1, 365], 'x2': [0.0, 1.0]}}
inp = {'mode': 'mode_1', 'method': 'method_1', 'other': {'x1': 1, 'x2': 1.0}}
def check(d, s):
    return all(b in s[a] if not isinstance(b, dict) else check(b, s[a]) for a, b in d.items())

print(check(inp, SCHEMA))

Output:

True

Edit: the solution above simply checks that a single key exists in an iterable of valid keys. However, to handle more specific checks (such as your fourth condition), you can build handlers for different types:

t = {'tuple':lambda x, y:x in y, 'list':lambda x, y:x > y[0] and x < y[-1]}
def check(d, s):
   return all(check(b, s[a]) if isinstance(b, dict) else t[type(s[a]).__name__](b, s[a]) for a, b in d.items())

Upvotes: -1

Andy_101
Andy_101

Reputation: 1306

Dictionary are like json so you can use jsonschema:

 import json

 from jsonschema import validate

 # A sample schema, YOU WILL HAVE TO DESIGN ONE .
 schema = {
     "type" : "object",
     "properties" : {
         "price" : {"type" : "number"},
         "name" : {"type" : "string"},
     },
 }

TESTING

# If no exception is raised by validate(), the instance is valid.
validate(instance={"name" : "Eggs", "price" : 34.99}, schema=schema)



validate(instance={"name" : "Eggs", "price" : "Invalid"}, schema=schema) 

#error

Traceback (most recent call last):
ValidationError: 'Invalid' is not of type 'number'

For more details check the documentation.

To get valid Json Schema for your schema you can use this.

Just replace ' with " and () with [].

Upvotes: 3

Mehrdad Pedramfar
Mehrdad Pedramfar

Reputation: 11073

You can try this recursive function:

def validate(input_, db): 
    for k,v in input_.items(): 
        if isinstance(v, dict): 
            return validate(v, db.get(k)) 
        else: 
            if v not in db.get(k): 
                return False 
    return True 

Then you call it:

In [21]: validate(inp, SCHEMA)                                                                                                                                                                                     
Out[21]: True

if you change your inp to:

In [16]: inp = { 
    ...:     'mode': 'mode_2', 
    ...:     'method': 'method_2', 
    ...:     'other': { 
    ...:         'x1': 4, # This is not valid
    ...:         'x2': 1.0 
    ...:     } 
    ...:  
    ...: }                                                                                                                                                                                                         

In [17]: validate(inp, SCHEMA)                                                                                                                                                                                     
Out[17]: False

or

In [20]: inp = { 
    ...:     'mode': 'mode_2', 
    ...:     'method': 'method_2', 
    ...:     'other': { 
    ...:         'x1': 1, 
    ...:         'x2': 1.0 
    ...:     } 
    ...:  
    ...: }                                                                                                                                                                                                         
In [21]: validate(inp, SCHEMA)                                                                                                                                                                                     
Out[21]: True

Upvotes: 3

Related Questions