2013-07-01 15 views
10

Ho provato voluptuous e schema, entrambi sono semplici e validi nella convalida, ma entrambi fanno una segnalazione degli errori basata su eccezioni, cioè falliscono al primo errore. C'è un modo per ottenere tutti gli errori di convalida dei dati in Voluptuous o Schema?Libreria di convalida Python semplice che segnala tutti gli errori di convalida anziché prima falliti?

Ho trovato jsonschema che sembra corrispondere ad alcuni dei requisiti, ma non ha la convalida per le chiavi dell'oggetto e la convalida basata su funzioni personalizzate (ad esempio lambda).

Requisito:

def myMethod(input_dict): 

    #input_dict should abide to this schema -> 
    # { 'id' : INT , 'name':'string 5-10 chars','hobbies': LIST OF STRINGS } 
    # for incorrect input like 
    # {'id': 'hello','name':'Dhruv','hobbies':[1,2,3] } 
    # I should be able to return all errors like 
    # ['id' is not integer,'hobbies' is not list of strings ] 
+0

Puoi dare un esempio di ciò che ti serve da una tale libreria? Se la validazione fallisce e si desidera continuare e non interrompere l'esecuzione, sembra un lavoro per la registrazione. –

+0

@BurhanKhalid Certo, cosa voglio convalidare l'input di un metodo e restituire tutti gli errori di validazione. – DhruvPathak

+0

https://pypi.python.org/pypi/voluptuous#error-reporting sembra dire che se i validatori generano eccezioni 'Invalid', verranno catturati e associati a un percorso. Non fa quello che vuoi? (Sono solo curioso, non l'ho mai usato) – rectummelancolique

risposta

1

Ho usato jsonschema prima ed è esattamente in grado di fare quello che vuoi che faccia. Inoltre, segnala gli errori in base all'eccezione, se lo desideri, ma puoi anche ripetere tutti gli errori di convalida trovati nel documento, ho scritto un breve programma di esempio che utilizza lo schema (vedi Json Schema V3 Spec) e stampa tutti gli errori trovati.

Modifica: Ho modificato lo script in modo che ora utilizzi un validatore personalizzato che consente di eseguire la convalida, il codice dovrebbe essere auto esplicativo. È possibile cercare la fonte jsonschema per informazioni su extend e in che modo i validatori sono estesi/codificati.

#!/usr/bin/env python2 

from jsonschema import Draft3Validator 
from jsonschema.exceptions import ValidationError 
from jsonschema.validators import extend 
import json 
import sys 

schema = { 
    "type": "object", 
    "required": True, 
    "additinalProperties": False, 
    "properties": { 
     "id": { 
      "type": "integer", 
      "required": True 
     }, 
     "name": { 
      "type": "string", 
      "required": True, 
      "minLength": 5, 
      "maxLength": 10 
     }, 
     "hobbies": { 
      "type": "array", 
      "customvalidator": "hobbies", 
      "required": True, 
      "items": { 
       "type": "string" 
      } 
     } 
    } 
} 


def hobbiesValidator(validator, value, instance, schema): 
    if 'Foo' not in instance: 
     yield ValidationError("You need to like Foo") 

    for field in instance: 
     if not validator.is_type(instance, "string"): 
      yield ValidationError("A hobby needs to be a string") 
     elif len(field) < 5: 
      err = "I like only hobbies which are len() >= 5, {} doesn't" 
      yield ValidationError(err.format(value)) 


def anotherHobbiesValidator(validator, value, instance, schema): 
    pass 


myCustomValidators = { 
    'hobbies': hobbiesValidator, 
    'anotherHobbies': anotherHobbiesValidator 
} 


def customValidatorDispatch(validator, value, instance, schema): 
    if value not in myCustomValidators: 
     err = '{} is unknown, we only know about: {}' 
     yield ValidationError(err.format(value, ', '.join(myCustomValidators.keys()))) 
    else: 
     errors = myCustomValidators[value](validator, value, instance, schema) 
     for error in errors: 
      yield error 


def myMethod(input_dict): 
    customValidator = extend(Draft3Validator, {'customvalidator': customValidatorDispatch}, 'MySchema') 
    validator = customValidator(schema) 

    errors = [e for e in validator.iter_errors(input_dict)] 
    if len(errors): 
     return errors 

    # do further processing here 
    return [] 

if __name__ == '__main__': 
    data = None 
    try: 
     f = open(sys.argv[1], 'r') 
     data = json.loads(f.read()) 
    except Exception, e: 
     print "Failed to parse input: {}".format(e) 
     sys.exit(-1) 

    errors = myMethod(data) 

    if not len(errors): 
     print "Input is valid!" 
    else: 
     print "Input is not valid, errors:" 
     for error in errors: 
      print "Err: ", error 

Input non valido:

$ cat invalid-input.json 
{ 
    "id": "hello", 
    "name": "Dhruv", 
    "hobbies": [ 
     1, 2, 3 
    ] 
} 

$ ./validate.py invalid-input.json 
Input is not valid, errors: 
Err: 1 is not of type 'string' 

Failed validating 'type' in schema['properties']['hobbies']['items']: 
    {'type': 'string'} 

On instance['hobbies'][0]: 
    1 
Err: 2 is not of type 'string' 

Failed validating 'type' in schema['properties']['hobbies']['items']: 
    {'type': 'string'} 

On instance['hobbies'][1]: 
    2 
Err: 3 is not of type 'string' 

Failed validating 'type' in schema['properties']['hobbies']['items']: 
    {'type': 'string'} 

On instance['hobbies'][2]: 
    3 
Err: You need to like Foo 

Failed validating 'customvalidator' in schema['properties']['hobbies']: 
    {'customvalidator': 'hobbies', 
    'items': {'type': 'string'}, 
    'required': True, 
    'type': 'array'} 

On instance['hobbies']: 
    [1, 2, 3] 
Err: A hobby needs to be a string 

Failed validating 'customvalidator' in schema['properties']['hobbies']: 
    {'customvalidator': 'hobbies', 
    'items': {'type': 'string'}, 
    'required': True, 
    'type': 'array'} 

On instance['hobbies']: 
    [1, 2, 3] 
Err: A hobby needs to be a string 

Failed validating 'customvalidator' in schema['properties']['hobbies']: 
    {'customvalidator': 'hobbies', 
    'items': {'type': 'string'}, 
    'required': True, 
    'type': 'array'} 

On instance['hobbies']: 
    [1, 2, 3] 
Err: A hobby needs to be a string 

Failed validating 'customvalidator' in schema['properties']['hobbies']: 
    {'customvalidator': 'hobbies', 
    'items': {'type': 'string'}, 
    'required': True, 
    'type': 'array'} 

On instance['hobbies']: 
    [1, 2, 3] 
Err: u'hello' is not of type 'integer' 

Failed validating 'type' in schema['properties']['id']: 
    {'required': True, 'type': 'integer'} 

On instance['id']: 
    u'hello' 

penso che le vostre esigenze sono ora occupati da questo script.

+0

ma jsonschema non soddisfa i requisiti menzionati nella domanda "non ha la convalida per le chiavi dell'oggetto e la convalida basata su funzioni personalizzate (ad es. Lambdas)." – DhruvPathak

+0

Ho aggiunto la convalida personalizzata al mio codice, ora dovrebbe fare quello che vuoi (quando apri il tuo schema e il tuo validatore). – Luminger

11

In realtà Voluptuous fornisce questa funzionalità, sebbene non ovvia nei documenti, è semplicemente una chiamata a MultipleInvalid.errors. La funzione restituisce un elenco delle eccezioni catturate Invalid dai validatori.

ad es.

try: 

    schema({...}) 

except MultipleInvalid as e: 
    # get the list of all `Invalid` exceptions caught 
    print e.errors 
+0

Grazie, proverò e vedrò se funziona. Sarebbe positivo se funzionasse in questo modo, dato che Voluptous è più flessibile di jsonschema. – DhruvPathak

+0

hai provato? :) – chutsu

+0

Sì, funziona. Grazie! – Kevin

Problemi correlati