|
1 | 1 | #!/usr/bin/env python
|
2 | 2 | # coding=utf-8
|
| 3 | +"""Validates a json file against a given json schema |
| 4 | +""" |
| 5 | + |
3 | 6 |
|
4 | 7 | import argparse
|
5 | 8 | import json
|
6 | 9 |
|
7 |
| -from jsonschema import validate, Draft4Validator |
| 10 | +from jsonschema import validate, Draft4Validator, ValidationError |
| 11 | +from skinfer import schema_inferer |
8 | 12 |
|
9 | 13 |
|
10 | 14 | def parse_args():
|
11 |
| - desc = 'Validates a json file against a given json schema.' |
12 |
| - parser = argparse.ArgumentParser(description=desc) |
13 |
| - parser.add_argument('json_schema', type=str, |
| 15 | + parser = argparse.ArgumentParser(description=__doc__) |
| 16 | + parser.add_argument('json_schema', |
14 | 17 | help='Path to the json schema file')
|
15 |
| - parser.add_argument('json_file', type=str, |
16 |
| - help='Path to the json file') |
| 18 | + parser.add_argument('instances', nargs='+', metavar='INSTANCE', |
| 19 | + help='JSON data files to be validated') |
| 20 | + parser.add_argument('--jsonlines', action='store_true', |
| 21 | + help='Assume instances are in JSON lines format') |
17 | 22 | return parser.parse_args()
|
18 | 23 |
|
19 | 24 |
|
20 |
| -def read_json(json_file): |
21 |
| - try: |
22 |
| - with open(json_file) as f: |
23 |
| - if json_file.endswith('.json'): |
24 |
| - return json.load(f) |
25 |
| - elif json_file.endswith('.jl'): |
26 |
| - return [json.loads(s) for s in f.readlines()] |
27 |
| - except Exception as e: |
28 |
| - print('Invalid json: %s' % e.message) |
29 |
| - |
30 |
| - |
31 |
| -def read_schema(json_schema): |
32 |
| - with open(args.json_schema) as f: |
33 |
| - schema = json.load(f) |
34 |
| - |
35 |
| - try: |
36 |
| - Draft4Validator.check_schema(schema) |
37 |
| - return schema |
38 |
| - except Exception as e: |
39 |
| - print('Invalid schema: %s' % e.message) |
| 25 | +def load_json(filepath): |
| 26 | + with open(filepath) as f: |
| 27 | + return json.load(f) |
40 | 28 |
|
41 | 29 |
|
42 |
| -def run(args): |
43 |
| - schema = read_schema(args.json_schema) |
44 |
| - json_data = read_json(args.json_file) |
| 30 | +def error_message(position, error): |
| 31 | + def convert(x): |
| 32 | + return '[%r]' % x |
| 33 | + field = ''.join(convert(x) for x in error.relative_path) |
| 34 | + return 'Failed validation for field %s in entry %d: %s' % (field, position, error.message) |
45 | 35 |
|
46 |
| - if not schema or not json_data: |
47 |
| - return |
48 | 36 |
|
| 37 | +def run_validation(schema, instances): |
49 | 38 | errors = 0
|
50 |
| - for line, item in enumerate(json_data, 1): |
| 39 | + total = 0 |
| 40 | + for i, item in enumerate(instances, 1): |
| 41 | + total += 1 |
51 | 42 | try:
|
52 | 43 | validate(item, schema)
|
53 |
| - except Exception as e: |
| 44 | + except ValidationError as e: |
54 | 45 | errors += 1
|
55 |
| - print('Error validating line %d: %s' % (line, e.message)) |
| 46 | + print(error_message(i, e)) |
| 47 | + |
| 48 | + print("%d errors found in %d items validated" % (errors, total)) |
| 49 | + |
56 | 50 |
|
57 |
| - print("%d items validated. %d errors." % (len(json_data), errors)) |
| 51 | +def run(args): |
| 52 | + schema = load_json(args.json_schema) |
| 53 | + Draft4Validator.check_schema(schema) |
| 54 | + |
| 55 | + try: |
| 56 | + instances = schema_inferer.load_samples(args.instances, args.jsonlines) |
| 57 | + run_validation(schema, instances) |
| 58 | + except ValueError as e: |
| 59 | + if 'Extra data:' in e.message: |
| 60 | + instances = schema_inferer.load_samples(args.instances, jsonlines=True) |
| 61 | + run_validation(schema, instances) |
| 62 | + else: |
| 63 | + raise |
58 | 64 |
|
59 | 65 |
|
60 | 66 | if __name__ == '__main__':
|
|
0 commit comments