From e8e1c169fb0d4a2648963a5b22cd5773d8b1ed0c Mon Sep 17 00:00:00 2001 From: p1c2u Date: Fri, 20 Feb 2026 16:37:40 +0000 Subject: [PATCH] Narrower handling around unresolved refs --- openapi_schema_validator/_keywords.py | 3 +- tests/integration/test_validators.py | 98 +++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/openapi_schema_validator/_keywords.py b/openapi_schema_validator/_keywords.py index b9650ad..a27e64b 100644 --- a/openapi_schema_validator/_keywords.py +++ b/openapi_schema_validator/_keywords.py @@ -10,6 +10,7 @@ from jsonschema._utils import find_additional_properties from jsonschema.exceptions import FormatError from jsonschema.exceptions import ValidationError +from jsonschema.exceptions import _WrappedReferencingError def handle_discriminator( @@ -53,7 +54,7 @@ def handle_discriminator( try: validator._validate_reference(ref=ref, instance=instance) - except Exception: + except _WrappedReferencingError: yield ValidationError( f"{instance!r} reference {ref!r} could not be resolved", context=[], diff --git a/tests/integration/test_validators.py b/tests/integration/test_validators.py index 85982fe..44e07e2 100644 --- a/tests/integration/test_validators.py +++ b/tests/integration/test_validators.py @@ -1,9 +1,17 @@ from base64 import b64encode +from typing import Any +from typing import cast import pytest from jsonschema import ValidationError +from jsonschema.exceptions import ( + _WrappedReferencingError as WrappedReferencingError, +) from referencing import Registry from referencing import Resource +from referencing.exceptions import InvalidAnchor +from referencing.exceptions import NoSuchAnchor +from referencing.exceptions import PointerToNowhere from referencing.jsonschema import DRAFT202012 from openapi_schema_validator import OAS30ReadValidator @@ -353,6 +361,96 @@ def test_oneof_required(self, validator_class): result = validator.validate(instance) assert result is None + @pytest.mark.parametrize( + "mapping_ref", + [ + "#/components/schemas/Missing", + "#missing-anchor", + "#bad/frag", + ], + ) + def test_discriminator_handles_unresolvable_reference_kinds( + self, mapping_ref + ): + schema = { + "oneOf": [{"$ref": "#/components/schemas/MountainHiking"}], + "discriminator": { + "propertyName": "discipline", + "mapping": {"mountain_hiking": mapping_ref}, + }, + "components": { + "schemas": { + "MountainHiking": { + "type": "object", + "properties": { + "discipline": {"type": "string"}, + "length": {"type": "integer"}, + }, + "required": ["discipline", "length"], + }, + }, + }, + } + + validator = OAS30Validator( + schema, + format_checker=oas30_format_checker, + ) + with pytest.raises( + ValidationError, + match=f"reference '{mapping_ref}' could not be resolved", + ): + validator.validate( + { + "discipline": "mountain_hiking", + "length": 10, + } + ) + + @pytest.mark.parametrize( + "mapping_ref, expected_cause", + [ + ("#/components/schemas/Missing", PointerToNowhere), + ("#missing-anchor", NoSuchAnchor), + ("#bad/frag", InvalidAnchor), + ], + ) + def test_discriminator_unresolvable_reference_causes( + self, mapping_ref, expected_cause + ): + schema = { + "oneOf": [{"$ref": "#/components/schemas/MountainHiking"}], + "discriminator": { + "propertyName": "discipline", + "mapping": {"mountain_hiking": mapping_ref}, + }, + "components": { + "schemas": { + "MountainHiking": { + "type": "object", + "properties": { + "discipline": {"type": "string"}, + "length": {"type": "integer"}, + }, + "required": ["discipline", "length"], + }, + }, + }, + } + + validator = OAS30Validator( + schema, + format_checker=oas30_format_checker, + ) + + with pytest.raises(WrappedReferencingError) as exc_info: + cast(Any, validator)._validate_reference( + ref=mapping_ref, + instance={"discipline": "mountain_hiking", "length": 10}, + ) + + assert isinstance(exc_info.value.__cause__, expected_cause) + @pytest.mark.parametrize( "schema_type", [