2013-07-01 17 views
10

Próbowałem już i , które są zarówno proste, jak i doskonałe w procesie sprawdzania poprawności, ale oba generują raportowanie błędów oparte na wyjątkach, tzn. Kończą się pierwszym błędem. Czy istnieje sposób uzyskać wszystkie błędy sprawdzania poprawności danych w Voluptuous lub Schema?Prosta biblioteka sprawdzania poprawności pytona, która zgłasza wszystkie błędy sprawdzania poprawności zamiast pierwszej nieudanej?

Znalazłem jsonschema, który wydaje się pasować do niektórych wymagań, ale nie ma sprawdzania poprawności kluczy obiektów i sprawdzania poprawności opartej na funkcjach niestandardowych (np. Lambdas).

Wymagania:

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

Czy możesz podać przykład tego, czego potrzebujesz z takiej biblioteki? Jeśli sprawdzanie poprawności nie powiedzie się i chcesz kontynuować i nie przerywać wykonywania, brzmi jak zadanie do logowania. –

+0

@BurhanKhalid Pewnie, co chcę zweryfikować dane wejściowe metody i zwrócić wszystkie błędy sprawdzania poprawności. – DhruvPathak

+0

https://pypi.python.org/pypi/voluptuous#error-reporting wydaje się mówić, że jeśli twoje walidatory podniosą wyjątki "Nieprawidłowe", zostaną przechwycone i powiązane ze ścieżką. Czy nie robi to, czego chcesz? (Jestem po prostu ciekawy, nigdy go nie używałem) – rectummelancolique

Odpowiedz

1

Użyłem jsonschema wcześniej i to jest dokładnie to w stanie robić to, co chcesz to zrobić. W razie potrzeby wykonuje także raportowanie błędów w oparciu o wyjątki, ale można również powtórzyć wszystkie błędy sprawdzania poprawności znalezione w dokumencie, napisałem krótki przykładowy program, który używa twojego schematu (zobacz Json Schema V3 Spec) i wypisuje wszystkie znalezione błędy.

Edytuj: Zmieniłem skrypt, więc teraz używa on niestandardowego walidatora, który pozwala ci przetasować własną walidację, kod powinien być zrozumiały. Możesz wyszukać źródło jsonschema dla informacji na extend oraz jak rozszerzenia są kodowane/poprawiane.

#!/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 

Nieprawidłowy wkład:

$ 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' 

Myślę, że wymagania są obecnie wypełnione przez tego skryptu.

+0

, ale jsonschema nie spełnia wymagań wymienionych w pytaniu "nie ma sprawdzania poprawności kluczy obiektów i sprawdzania poprawności opartej na funkcjach niestandardowych (np. Lambdas)." – DhruvPathak

+0

Dodałem niestandardowe sprawdzanie poprawności do mojego kodu, powinien teraz zrobić to, co chcesz (po uruchomieniu własnego schematu i walidatora). – Luminger

11

Faktycznie Voluptuous zapewnia tę funkcję, chociaż nie jest to oczywiste w dokumentach, jest to po prostu połączenie z MultipleInvalid.errors. Ta funkcja zwraca listę złapanych wyjątków z walidatorów.

np.

try: 

    schema({...}) 

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

Dzięki, spróbuję i zobaczymy, czy to działa. Byłoby dobrze, gdyby działało w ten sposób, ponieważ wybuchowość jest bardziej elastyczna niż jsonschema. – DhruvPathak

+0

czy próbowałeś? :) – chutsu

+0

Tak, działa. Dzięki! – Kevin

Powiązane problemy