Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/nbformat/json_compat.py: 37%
59 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-01 06:54 +0000
1"""
2Common validator wrapper to provide a uniform usage of other schema validation
3libraries.
4"""
5# Copyright (c) Jupyter Development Team.
6# Distributed under the terms of the Modified BSD License.
8import os
10import fastjsonschema
11import jsonschema
12from fastjsonschema import JsonSchemaException as _JsonSchemaException
13from jsonschema import Draft4Validator as _JsonSchemaValidator
14from jsonschema import ErrorTree, ValidationError
17class JsonSchemaValidator:
18 """A json schema validator."""
20 name = "jsonschema"
22 def __init__(self, schema):
23 """Initialize the validator."""
24 self._schema = schema
25 self._default_validator = _JsonSchemaValidator(schema) # Default
26 self._validator = self._default_validator
28 def validate(self, data):
29 """Validate incoming data."""
30 self._default_validator.validate(data)
32 def iter_errors(self, data, schema=None):
33 """Iterate over errors in incoming data."""
34 if schema is None:
35 return self._default_validator.iter_errors(data)
36 if hasattr(self._default_validator, "evolve"):
37 return self._default_validator.evolve(schema=schema).iter_errors(data)
38 return self._default_validator.iter_errors(data, schema)
40 def error_tree(self, errors):
41 """Create an error tree for the errors."""
42 return ErrorTree(errors=errors)
45class FastJsonSchemaValidator(JsonSchemaValidator):
46 """A schema validator using fastjsonschema."""
48 name = "fastjsonschema"
50 def __init__(self, schema):
51 """Initialize the validator."""
52 super().__init__(schema)
53 self._validator = fastjsonschema.compile(schema)
55 def validate(self, data):
56 """Validate incoming data."""
57 try:
58 self._validator(data)
59 except _JsonSchemaException as error:
60 raise ValidationError(str(error), schema_path=error.path) from error
62 def iter_errors(self, data, schema=None):
63 """Iterate over errors in incoming data."""
64 if schema is not None:
65 return super().iter_errors(data, schema)
67 errors = []
68 validate_func = self._validator
69 try:
70 validate_func(data)
71 except _JsonSchemaException as error:
72 errors = [ValidationError(str(error), schema_path=error.path)]
74 return errors
76 def error_tree(self, errors):
77 """Create an error tree for the errors."""
78 # fastjsonschema's exceptions don't contain the same information that the jsonschema ValidationErrors
79 # do. This method is primarily used for introspecting metadata schema failures so that we can strip
80 # them if asked to do so in `nbformat.validate`.
81 # Another way forward for compatibility: we could distill both validator errors into a custom collection
82 # for this data. Since implementation details of ValidationError is used elsewhere, we would probably
83 # just use this data for schema introspection.
84 msg = "JSON schema error introspection not enabled for fastjsonschema"
85 raise NotImplementedError(msg)
88_VALIDATOR_MAP = [
89 ("fastjsonschema", fastjsonschema, FastJsonSchemaValidator),
90 ("jsonschema", jsonschema, JsonSchemaValidator),
91]
92VALIDATORS = [item[0] for item in _VALIDATOR_MAP]
95def _validator_for_name(validator_name):
96 if validator_name not in VALIDATORS:
97 msg = f"Invalid validator '{validator_name}' value!\nValid values are: {VALIDATORS}"
98 raise ValueError(msg)
100 for name, module, validator_cls in _VALIDATOR_MAP:
101 if module and validator_name == name:
102 return validator_cls
103 # we always return something.
104 msg = f"Missing validator for {repr(validator_name)}"
105 raise ValueError(msg)
108def get_current_validator():
109 """
110 Return the default validator based on the value of an environment variable.
111 """
112 validator_name = os.environ.get("NBFORMAT_VALIDATOR", "fastjsonschema")
113 return _validator_for_name(validator_name)