def _validate(database: Mapping[str, Any], schemaPath: str) -> None: """ Validates a database against a schema. Note: The `jsonschema` library validates python data structures directly and produces nice error messages, but validation is slow. The `rapidjson` library validates much faster, however it produces poor error messages. For this reason rapidjson is used for the initial validation, and jsonschema is used if there is a failure. Args: database: The database to be validated. schemaPath: The location of the schema. """ with open(schemaPath, "r", encoding="utf-8") as fileObj: schema: Dict[str, Any] = json.load(fileObj) validate: Callable[[str], None] = rapidjson.Validator(rapidjson.dumps(schema)) try: validate(rapidjson.dumps(database)) except rapidjson.ValidationError as rapidjsonExc: try: jsonschema.validate(database, schema) except jsonschema.ValidationError as jsonschemaExc: raise SchemaValidationError(str(jsonschemaExc)) from jsonschemaExc else: logger.warning( f"Error: jsonschema did not raise an exception, whereas rapidjson raised {rapidjsonExc}." ) raise SchemaValidationError(str(rapidjsonExc)) from rapidjsonExc
def _load_schema(name, path=__file__): """Load a schema from disk""" path = os.path.join(os.path.dirname(path), name + '.yaml') with open(path) as handle: schema = yaml.safe_load(handle) fast_schema = rapidjson.Validator(rapidjson.dumps(schema)) return path, (schema, fast_schema)
def load_schemas(path): """return a dictionary containing "{namespace}.{doctype}.{doctype}" to validator""" schemas = {} for root, _, files in os.walk(path): for name in files: if name.endswith(".schema.json"): schemafile = os.path.join(root, name) name = parse_schema_name(schemafile) with open(schemafile, "r") as f: schemas[name] = rapidjson.Validator(f.read()) return schemas
def _validate(self, candidate): """Checks whether a legend is valid or not. Args: candidate (dict): Candidate legend. Raises: Exception if legend does not fit the schmea """ validate = rapidjson.Validator(self.schema) validate(rapidjson.dumps(candidate)) return candidate
def save(path, result): try: validate = json.Validator(json.dumps(REPORT_SCHEMA)) validate(json.dumps(result)) except ValueError as error: print(error.args) exit(-1) os.makedirs(os.path.dirname(path), exist_ok=True) print("Writing to {}".format(path)) with open(path, 'w') as f: json.dump(result, f, indent=4, sort_keys=True)
def load_namespace(base, namespace): """Return a dictionary of all files with the `*.schema.json` suffix. Namespaces help differentiate ingestion systems. For example, `telemetry` refers to pings generated by various Firefox products. Other namespaced ingestion pipelines may exists due to generic ingestion. """ schemas = dict() for root, _, files in os.walk(os.path.join(base, namespace)): for name in files: if not name.endswith(".schema.json"): continue with open(os.path.join(root, name), "r") as f: key = name.split(".schema.json")[0] schemas[key] = rapidjson.Validator(f.read()) print("Registered {}.{} ".format(namespace, key)) return schemas
def test_failed_validation(): tracemalloc.start() schema = """{ "$schema": "http://json-schema.org/draft-04/schema#", "required": ["id", "name"], "type": "object", "properties": { "id": {"type": "integer"}, "name": {"type": "string"} } }""".encode("utf-8") obj = """{ "id": 50 }""".encode("utf-8") validate = rj.Validator(schema) snapshot1 = tracemalloc.take_snapshot().filter_traces( (tracemalloc.Filter(True, __file__), )) # start the test for j in range(1000): try: validate(obj) except rj.ValidationError: pass del j gc.collect() snapshot2 = tracemalloc.take_snapshot().filter_traces( (tracemalloc.Filter(True, __file__), )) top_stats = snapshot2.compare_to(snapshot1, 'lineno') tracemalloc.stop() for stat in top_stats[:10]: assert stat.count_diff < 3
def test_invalid(schema, json, details): validate = rj.Validator(schema) with pytest.raises(ValueError) as error: validate(json) assert error.value.args == details
def test_valid(schema, json): validate = rj.Validator(schema) validate(json)
def test_invalid_json(): validate = rj.Validator('""') pytest.raises(ValueError, validate, '') pytest.raises(ValueError, validate, '"')
def test_additional_and_pattern_properties_valid(schema, json): validate = rj.Validator(schema) validate(json)
def test_invalid_json(): validate = rj.Validator('""') pytest.raises(rj.JSONDecodeError, validate, '') pytest.raises(rj.JSONDecodeError, validate, '"')