diff --git a/src/palace/manager/core/opds_schema.py b/src/palace/manager/core/opds_schema.py index 09568b02b..c1a20129e 100644 --- a/src/palace/manager/core/opds_schema.py +++ b/src/palace/manager/core/opds_schema.py @@ -6,7 +6,7 @@ from urllib.parse import urlparse from jsonschema import Draft7Validator, validators -from jsonschema._utils import extras_msg +from jsonschema._keywords import additionalProperties, pattern, patternProperties from jsonschema.exceptions import ValidationError from jsonschema.protocols import Validator from referencing import Registry @@ -66,42 +66,25 @@ def opds2_pattern_validator( ) -> Generator[ValidationError, None, None]: """ Validation function to validate a patten element. - - The bulk of this function is copied from the jsonschema library. It was copied from - jsonschema._keywords.pattern. They put their validation functions in a private module, - and the docs mention not to extending them. So we copied the function here. """ patrn = opds2_regex_replace(patrn) - if validator.is_type(instance, "string") and not re.search(patrn, instance): - yield ValidationError(f"{instance!r} does not match {patrn!r}") + yield from pattern(validator, patrn, instance, schema) def opds2_pattern_properties_validator( validator: Validator, - patternProperties: dict[str, Any], + patrnProps: dict[str, Any], instance: dict[str, Any], schema: dict[str, Any], ) -> Generator[ValidationError, None, None]: """ Validation function to validate a pattenProperties element. - - The bulk of this function is copied from the jsonschema library. It was copied from - jsonschema._keywords.patternProperties. They put their validation functions in a private module, - and the docs mention not to extending them. So we copied the function here. """ - if not validator.is_type(instance, "object"): - return - - for pattern, subschema in patternProperties.items(): - pattern = opds2_regex_replace(pattern) - for k, v in instance.items(): - if re.search(pattern, k): - yield from validator.descend( - v, - subschema, - path=k, - schema_path=pattern, - ) + filtered_patterns = { + opds2_regex_replace(pattern): subschema + for pattern, subschema in patrnProps.items() + } + yield from patternProperties(validator, filtered_patterns, instance, schema) def opds2_additional_properties_validator( @@ -112,44 +95,14 @@ def opds2_additional_properties_validator( ) -> Generator[ValidationError, None, None]: """ Validation function to validate a pattenProperties element. - - The bulk of this function is copied from the jsonschema library. It was copied from - jsonschema._keywords.additionalProperties. They put their validation functions in a private module, - and the docs mention not to extending them. So we copied the function here. """ - - def additional_properties( - instance: dict[str, Any], schema: dict[str, Any] - ) -> Generator[str, None, None]: - properties = schema.get("properties", {}) - patterns = "|".join(schema.get("patternProperties", {})) - patterns = opds2_regex_replace(patterns) - for property in instance: - if property not in properties: - if patterns and re.search(patterns, property): - continue - yield property - - if not validator.is_type(instance, "object"): - return - - extras = set(additional_properties(instance, schema)) - - if validator.is_type(aP, "object"): - for extra in extras: - yield from validator.descend(instance[extra], aP, path=extra) - elif not aP and extras: - if "patternProperties" in schema: - verb = "does" if len(extras) == 1 else "do" - joined = ", ".join(repr(each) for each in sorted(extras)) - patterns = ", ".join( - repr(each) for each in sorted(schema["patternProperties"]) - ) - error = f"{joined} {verb} not match any of the regexes: {patterns}" - yield ValidationError(error) - else: - error = "Additional properties are not allowed (%s %s unexpected)" - yield ValidationError(error % extras_msg(sorted(extras, key=str))) + if "patternProperties" in schema: + schema = schema.copy() + schema["patternProperties"] = { + opds2_regex_replace(patrn): subschema + for patrn, subschema in schema["patternProperties"].items() + } + yield from additionalProperties(validator, aP, instance, schema) def opds2_schema_registry() -> Registry: