def compareProperties( validator: jsonschema.Draft7Validator, compare: Dict, instance: Any, schema: Dict ) -> Iterator[jsonschema.ValidationError]: """ compareProperties allows a schema to compare values in the instance against each other. Amazingly, json-schema does not have a built-in way to do this. Example: ensuring that hyperparmeter minval is less than maxval: "compareProperties": { "type": "a<b", "a": "minval", "b": "maxval" } """ if not validator.is_type(instance, "object"): return def get_by_path(path: str) -> Any: obj = instance for key in path.split("."): if not obj: return None obj = obj.get(key) return obj a_path = compare["a"] a = get_by_path(a_path) b_path = compare["b"] b = get_by_path(b_path) if a is None or b is None: return typ = compare["type"] if typ == "a<b": if a >= b: yield jsonschema.ValidationError(f"{a_path} must be less than {b_path}") return if typ == "a<=b": if a > b: yield jsonschema.ValidationError(f"{a_path} must be less than {b_path}") return if typ == "a_is_subdir_of_b": a_norm = os.path.normpath(a) b_norm = os.path.normpath(b) if os.path.isabs(a_norm): if not a_norm.startswith(b_norm): yield jsonschema.ValidationError(f"{a_path} must be a subdirectory of {b_path}") else: if a_norm.startswith(".."): yield jsonschema.ValidationError(f"{a_path} must be a subdirectory of {b_path}") return raise ValueError(f"unrecognized comparison {compare[typ]}")
def set_defaults(validator: Draft7Validator, properties: Mapping, instance: Draft7Validator, schema: Mapping) -> Union[Generator, Draft7Validator]: if not validator.is_type(instance, "object"): return for key, subschema in properties.items(): if "default" in subschema: instance.setdefault(key, subschema["default"]) for error in validate_properties(validator, properties, instance, schema): yield error
def disallowProperties( validator: jsonschema.Draft7Validator, disallowed: Dict, instance: Any, schema: Dict ) -> Iterator[jsonschema.ValidationError]: """ disallowProperties is for restricting which properties are allowed in an object with per-property, such as when we allow a k8s pod spec with some fields disallowed. Example: The "pod_spec" property of the environment config: "pod_spec": { "type": "object", "disallowProperties": { "name": "pod Name is not a configurable option", "name_space": "pod NameSpace is not a configurable option" } } """ if not validator.is_type(instance, "object"): return for prop in instance: if prop in disallowed: msg = disallowed[prop] yield jsonschema.ValidationError(msg)
def compareProperties(validator: jsonschema.Draft7Validator, compare: Dict, instance: Any, schema: Dict) -> Iterator[jsonschema.ValidationError]: """ compareProperties allows a schema to compare values in the instance against each other. Amazingly, json-schema does not have a built-in way to do this. Example: ensuring that hyperparmeter minval is less than maxval: "compareProperties": { "type": "a<b", "a": "minval", "b": "maxval" } """ if not validator.is_type(instance, "object"): return def get_by_path(path: str) -> Any: obj = instance for key in path.split("."): if not obj: return None obj = obj.get(key) return obj a_path = compare["a"] a = get_by_path(a_path) b_path = compare["b"] b = get_by_path(b_path) if a is None or b is None: return typ = compare["type"] if typ == "a<b": if a >= b: yield jsonschema.ValidationError( f"{a_path} must be less than {b_path}") return if typ == "same_units": # same_units refers to a Length object. if not isinstance(a, dict) or not isinstance(b, dict): return if next(iter(a.keys())) != next(iter(b.keys())): yield jsonschema.ValidationError( f"{a_path} must be defined in the same units as {b_path}") return if typ == "length_a<length_b": # length_a<length_b compares two length objects. if not isinstance(a, dict) or not isinstance(b, dict): return # Assume the same units. length_a = next(iter(a.values())) length_b = next(iter(b.values())) if not isinstance(length_a, int) or not isinstance(length_b, int): return if length_a >= length_b: yield jsonschema.ValidationError( f"{a_path} must be less than {b_path}") return if typ == "a_is_subdir_of_b": a_norm = os.path.normpath(a) b_norm = os.path.normpath(b) if os.path.isabs(a_norm): if not a_norm.startswith(b_norm): yield jsonschema.ValidationError( f"{a_path} must be a subdirectory of {b_path}") else: if a_norm.startswith(".."): yield jsonschema.ValidationError( f"{a_path} must be a subdirectory of {b_path}") return raise ValueError(f"unrecognized comparison {compare[typ]}")