Skip to content

Commit 37db3bf

Browse files
committed
schema properties validation recursion fix
1 parent ee153b2 commit 37db3bf

File tree

5 files changed

+35
-8
lines changed

5 files changed

+35
-8
lines changed

openapi_spec_validator/schemas/utils.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
from typing import Tuple
88

99
if sys.version_info >= (3, 9):
10-
from importlib.resources import as_file, files
10+
from importlib.resources import as_file
11+
from importlib.resources import files
1112
else:
12-
from importlib_resources import as_file, files
13+
from importlib_resources import as_file
14+
from importlib_resources import files
15+
1316
from jsonschema_spec.readers import FilePathReader
1417

1518

openapi_spec_validator/validation/validators.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def __init__(
6565
self.resolver_handlers = resolver_handlers
6666

6767
self.operation_ids_registry: Optional[List[str]] = None
68+
self.schema_ids_registry: Optional[List[int]] = None
6869
self.resolver = None
6970

7071
def validate(
@@ -82,6 +83,7 @@ def iter_errors(
8283
self, instance: Mapping[Hashable, Any], spec_url: str = ""
8384
) -> Iterator[ValidationError]:
8485
self.operation_ids_registry = []
86+
self.schema_ids_registry = []
8587
self.resolver = self._get_resolver(spec_url, instance)
8688

8789
yield from self.schema_validator.iter_errors(instance)
@@ -248,7 +250,12 @@ def _iter_schema_errors(
248250
if not hasattr(schema.content(), "__getitem__"):
249251
return
250252

251-
schema_type = schema.getkey("type")
253+
assert self.schema_ids_registry is not None
254+
schema_id = id(schema.content())
255+
if schema_id in self.schema_ids_registry:
256+
return
257+
self.schema_ids_registry.append(schema_id)
258+
252259
nested_properties = []
253260
if "allOf" in schema:
254261
all_of = schema / "allOf"
@@ -294,7 +301,7 @@ def _iter_schema_errors(
294301
)
295302

296303
if "properties" in schema:
297-
props = schema /"properties"
304+
props = schema / "properties"
298305
for _, prop_schema in props.items():
299306
yield from self._iter_schema_errors(
300307
prop_schema,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
openapi: 3.0.0
2+
info:
3+
version: '1.0.0'
4+
title: 'Some Schema'
5+
paths: {}
6+
components:
7+
schemas:
8+
SomeDataType:
9+
type: object
10+
properties:
11+
id:
12+
type: integer
13+
prop1:
14+
$ref: '#/components/schemas/SomeDataType'
15+
prop2:
16+
type: string

tests/integration/validation/test_exceptions.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,9 @@ def test_parameter_custom_format_checker_not_found(self, validator_v30):
456456
errors_list = list(errors)
457457
assert errors_list == []
458458

459-
def test_parameter_default_value_custom_format_invalid(self, validator_v30):
459+
def test_parameter_default_value_custom_format_invalid(
460+
self, validator_v30
461+
):
460462
from openapi_schema_validator import oas30_format_checker
461463

462464
@oas30_format_checker.checks("custom")
@@ -498,6 +500,4 @@ def validate(to_validate) -> bool:
498500
errors_list = list(errors)
499501
assert len(errors_list) == 1
500502
assert errors_list[0].__class__ == OpenAPIValidationError
501-
assert errors_list[0].message == (
502-
"'invalid' is not a 'custom'"
503-
)
503+
assert errors_list[0].message == ("'invalid' is not a 'custom'")

tests/integration/validation/test_validators.py

+1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def local_test_suite_file_path(self, test_file):
6666
"petstore.yaml",
6767
"petstore-separate/spec/openapi.yaml",
6868
"parent-reference/openapi.yaml",
69+
"property-recursive.yaml",
6970
],
7071
)
7172
def test_valid(self, factory, validator_v30, spec_file):

0 commit comments

Comments
 (0)