Blame tools/extra/packager/jsonschema-2.3.0/json/bin/jsonschema_suite

Packit 534379
#! /usr/bin/env python
Packit 534379
from __future__ import print_function
Packit 534379
import sys
Packit 534379
import textwrap
Packit 534379
Packit 534379
try:
Packit 534379
    import argparse
Packit 534379
except ImportError:
Packit 534379
    print(textwrap.dedent("""
Packit 534379
        The argparse library could not be imported. jsonschema_suite requires
Packit 534379
        either Python 2.7 or for you to install argparse. You can do so by
Packit 534379
        running `pip install argparse`, `easy_install argparse` or by
Packit 534379
        downloading argparse and running `python2.6 setup.py install`.
Packit 534379
Packit 534379
        See https://pypi.python.org/pypi/argparse for details.
Packit 534379
    """.strip("\n")))
Packit 534379
    sys.exit(1)
Packit 534379
Packit 534379
import errno
Packit 534379
import fnmatch
Packit 534379
import json
Packit 534379
import os
Packit 534379
import random
Packit 534379
import shutil
Packit 534379
import unittest
Packit 534379
import warnings
Packit 534379
Packit 534379
if getattr(unittest, "skipIf", None) is None:
Packit 534379
    unittest.skipIf = lambda cond, msg : lambda fn : fn
Packit 534379
Packit 534379
try:
Packit 534379
    import jsonschema
Packit 534379
except ImportError:
Packit 534379
    jsonschema = None
Packit 534379
else:
Packit 534379
    validators = getattr(
Packit 534379
        jsonschema.validators, "validators", jsonschema.validators
Packit 534379
    )
Packit 534379
Packit 534379
Packit 534379
ROOT_DIR = os.path.join(
Packit 534379
    os.path.dirname(__file__), os.pardir).rstrip("__pycache__")
Packit 534379
SUITE_ROOT_DIR = os.path.join(ROOT_DIR, "tests")
Packit 534379
Packit 534379
REMOTES = {
Packit 534379
    "integer.json": {"type": "integer"},
Packit 534379
    "subSchemas.json": {
Packit 534379
        "integer": {"type": "integer"},
Packit 534379
        "refToInteger": {"$ref": "#/integer"},
Packit 534379
    },
Packit 534379
    "folder/folderInteger.json": {"type": "integer"}
Packit 534379
}
Packit 534379
REMOTES_DIR = os.path.join(ROOT_DIR, "remotes")
Packit 534379
Packit 534379
TESTSUITE_SCHEMA = {
Packit 534379
    "$schema": "http://json-schema.org/draft-03/schema#",
Packit 534379
    "type": "array",
Packit 534379
    "items": {
Packit 534379
        "type": "object",
Packit 534379
        "properties": {
Packit 534379
            "description": {"type": "string", "required": True},
Packit 534379
            "schema": {"required": True},
Packit 534379
            "tests": {
Packit 534379
                "type": "array",
Packit 534379
                "items": {
Packit 534379
                    "type": "object",
Packit 534379
                    "properties": {
Packit 534379
                        "description": {"type": "string", "required": True},
Packit 534379
                        "data": {"required": True},
Packit 534379
                        "valid": {"type": "boolean", "required": True}
Packit 534379
                    },
Packit 534379
                    "additionalProperties": False
Packit 534379
                },
Packit 534379
                "minItems": 1
Packit 534379
            }
Packit 534379
        },
Packit 534379
        "additionalProperties": False,
Packit 534379
        "minItems": 1
Packit 534379
    }
Packit 534379
}
Packit 534379
Packit 534379
Packit 534379
def files(paths):
Packit 534379
    for path in paths:
Packit 534379
        with open(path) as test_file:
Packit 534379
            yield json.load(test_file)
Packit 534379
Packit 534379
Packit 534379
def groups(paths):
Packit 534379
    for test_file in files(paths):
Packit 534379
        for group in test_file:
Packit 534379
            yield group
Packit 534379
Packit 534379
Packit 534379
def cases(paths):
Packit 534379
    for test_group in groups(paths):
Packit 534379
        for test in test_group["tests"]:
Packit 534379
            test["schema"] = test_group["schema"]
Packit 534379
            yield test
Packit 534379
Packit 534379
Packit 534379
def collect(root_dir):
Packit 534379
    for root, dirs, files in os.walk(root_dir):
Packit 534379
        for filename in fnmatch.filter(files, "*.json"):
Packit 534379
            yield os.path.join(root, filename)
Packit 534379
Packit 534379
Packit 534379
class SanityTests(unittest.TestCase):
Packit 534379
    @classmethod
Packit 534379
    def setUpClass(cls):
Packit 534379
        print("Looking for tests in %s" % SUITE_ROOT_DIR)
Packit 534379
        cls.test_files = list(collect(SUITE_ROOT_DIR))
Packit 534379
        print("Found %s test files" % len(cls.test_files))
Packit 534379
        assert cls.test_files, "Didn't find the test files!"
Packit 534379
Packit 534379
    def test_all_files_are_valid_json(self):
Packit 534379
        for path in self.test_files:
Packit 534379
            with open(path) as test_file:
Packit 534379
                try:
Packit 534379
                    json.load(test_file)
Packit 534379
                except ValueError as error:
Packit 534379
                    self.fail("%s contains invalid JSON (%s)" % (path, error))
Packit 534379
Packit 534379
    def test_all_descriptions_have_reasonable_length(self):
Packit 534379
        for case in cases(self.test_files):
Packit 534379
            descript = case["description"]
Packit 534379
            self.assertLess(
Packit 534379
                len(descript),
Packit 534379
                60,
Packit 534379
                "%r is too long! (keep it to less than 60 chars)" % (descript,)
Packit 534379
            )
Packit 534379
Packit 534379
    def test_all_descriptions_are_unique(self):
Packit 534379
        for group in groups(self.test_files):
Packit 534379
            descriptions = set(test["description"] for test in group["tests"])
Packit 534379
            self.assertEqual(
Packit 534379
                len(descriptions),
Packit 534379
                len(group["tests"]),
Packit 534379
                "%r contains a duplicate description" % (group,)
Packit 534379
            )
Packit 534379
Packit 534379
    @unittest.skipIf(jsonschema is None, "Validation library not present!")
Packit 534379
    def test_all_schemas_are_valid(self):
Packit 534379
        for schema in os.listdir(SUITE_ROOT_DIR):
Packit 534379
            schema_validator = validators.get(schema)
Packit 534379
            if schema_validator is not None:
Packit 534379
                test_files = collect(os.path.join(SUITE_ROOT_DIR, schema))
Packit 534379
                for case in cases(test_files):
Packit 534379
                    try:
Packit 534379
                        schema_validator.check_schema(case["schema"])
Packit 534379
                    except jsonschema.SchemaError as error:
Packit 534379
                        self.fail("%s contains an invalid schema (%s)" %
Packit 534379
                                  (case, error))
Packit 534379
            else:
Packit 534379
                warnings.warn("No schema validator for %s" % schema)
Packit 534379
Packit 534379
    @unittest.skipIf(jsonschema is None, "Validation library not present!")
Packit 534379
    def test_suites_are_valid(self):
Packit 534379
        validator = jsonschema.Draft3Validator(TESTSUITE_SCHEMA)
Packit 534379
        for tests in files(self.test_files):
Packit 534379
            try:
Packit 534379
                validator.validate(tests)
Packit 534379
            except jsonschema.ValidationError as error:
Packit 534379
                self.fail(str(error))
Packit 534379
Packit 534379
    def test_remote_schemas_are_updated(self):
Packit 534379
        for url, schema in REMOTES.items():
Packit 534379
            filepath = os.path.join(REMOTES_DIR, url)
Packit 534379
            with open(filepath) as schema_file:
Packit 534379
                self.assertEqual(json.load(schema_file), schema)
Packit 534379
Packit 534379
Packit 534379
def main(arguments):
Packit 534379
    if arguments.command == "check":
Packit 534379
        suite = unittest.TestLoader().loadTestsFromTestCase(SanityTests)
Packit 534379
        result = unittest.TextTestRunner(verbosity=2).run(suite)
Packit 534379
        sys.exit(not result.wasSuccessful())
Packit 534379
    elif arguments.command == "flatten":
Packit 534379
        selected_cases = [case for case in cases(collect(arguments.version))]
Packit 534379
Packit 534379
        if arguments.randomize:
Packit 534379
            random.shuffle(selected_cases)
Packit 534379
Packit 534379
        json.dump(selected_cases, sys.stdout, indent=4, sort_keys=True)
Packit 534379
    elif arguments.command == "remotes":
Packit 534379
        json.dump(REMOTES, sys.stdout, indent=4, sort_keys=True)
Packit 534379
    elif arguments.command == "dump_remotes":
Packit 534379
        if arguments.update:
Packit 534379
            shutil.rmtree(arguments.out_dir, ignore_errors=True)
Packit 534379
Packit 534379
        try:
Packit 534379
            os.makedirs(arguments.out_dir)
Packit 534379
        except OSError as e:
Packit 534379
            if e.errno == errno.EEXIST:
Packit 534379
                print("%s already exists. Aborting." % arguments.out_dir)
Packit 534379
                sys.exit(1)
Packit 534379
            raise
Packit 534379
Packit 534379
        for url, schema in REMOTES.items():
Packit 534379
            filepath = os.path.join(arguments.out_dir, url)
Packit 534379
Packit 534379
            try:
Packit 534379
                os.makedirs(os.path.dirname(filepath))
Packit 534379
            except OSError as e:
Packit 534379
                if e.errno != errno.EEXIST:
Packit 534379
                    raise
Packit 534379
Packit 534379
            with open(filepath, "wb") as out_file:
Packit 534379
                json.dump(schema, out_file, indent=4, sort_keys=True)
Packit 534379
    elif arguments.command == "serve":
Packit 534379
        try:
Packit 534379
            from flask import Flask, jsonify
Packit 534379
        except ImportError:
Packit 534379
            print(textwrap.dedent("""
Packit 534379
                The Flask library is required to serve the remote schemas.
Packit 534379
Packit 534379
                You can install it by running `pip install Flask`.
Packit 534379
Packit 534379
                Alternatively, see the `jsonschema_suite remotes` or
Packit 534379
                `jsonschema_suite dump_remotes` commands to create static files
Packit 534379
                that can be served with your own web server.
Packit 534379
            """.strip("\n")))
Packit 534379
            sys.exit(1)
Packit 534379
Packit 534379
        app = Flask(__name__)
Packit 534379
Packit 534379
        @app.route("/<path:path>")
Packit 534379
        def serve_path(path):
Packit 534379
            if path in REMOTES:
Packit 534379
                return jsonify(REMOTES[path])
Packit 534379
            return "Document does not exist.", 404
Packit 534379
Packit 534379
        app.run(port=1234)
Packit 534379
Packit 534379
Packit 534379
parser = argparse.ArgumentParser(
Packit 534379
    description="JSON Schema Test Suite utilities",
Packit 534379
)
Packit 534379
subparsers = parser.add_subparsers(help="utility commands", dest="command")
Packit 534379
Packit 534379
check = subparsers.add_parser("check", help="Sanity check the test suite.")
Packit 534379
Packit 534379
flatten = subparsers.add_parser(
Packit 534379
    "flatten",
Packit 534379
    help="Output a flattened file containing a selected version's test cases."
Packit 534379
)
Packit 534379
flatten.add_argument(
Packit 534379
    "--randomize",
Packit 534379
    action="store_true",
Packit 534379
    help="Randomize the order of the outputted cases.",
Packit 534379
)
Packit 534379
flatten.add_argument(
Packit 534379
    "version", help="The directory containing the version to output",
Packit 534379
)
Packit 534379
Packit 534379
remotes = subparsers.add_parser(
Packit 534379
    "remotes",
Packit 534379
    help="Output the expected URLs and their associated schemas for remote "
Packit 534379
         "ref tests as a JSON object."
Packit 534379
)
Packit 534379
Packit 534379
dump_remotes = subparsers.add_parser(
Packit 534379
    "dump_remotes", help="Dump the remote ref schemas into a file tree",
Packit 534379
)
Packit 534379
dump_remotes.add_argument(
Packit 534379
    "--update",
Packit 534379
    action="store_true",
Packit 534379
    help="Update the remotes in an existing directory.",
Packit 534379
)
Packit 534379
dump_remotes.add_argument(
Packit 534379
    "--out-dir",
Packit 534379
    default=REMOTES_DIR,
Packit 534379
    type=os.path.abspath,
Packit 534379
    help="The output directory to create as the root of the file tree",
Packit 534379
)
Packit 534379
Packit 534379
serve = subparsers.add_parser(
Packit 534379
    "serve",
Packit 534379
    help="Start a webserver to serve schemas used by remote ref tests."
Packit 534379
)
Packit 534379
Packit 534379
if __name__ == "__main__":
Packit 534379
    main(parser.parse_args())