Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6a766b6

Browse files
committed
fix: Fix IndexError if a schema has an applicator keyword at top-level
1 parent db23985 commit 6a766b6

3 files changed

Lines changed: 70 additions & 15 deletions

File tree

ocdskit/commands/normalize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def handle(self):
7373
remove_fields=set(self.args.ignore_fields),
7474
)
7575

76-
# Get valid JSON Schema, and reduce its size.
76+
# Get valid JSON Schema, and reduce its size. NOTE: These operations can in principle be a separate command.
7777
if schema.get("openapi", "").startswith("3.0"):
7878
schema = convert_from_oas3(schema, get_only=self.args.get_only)
7979
if self.args.remove_private_fields:

ocdskit/normalize.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ def _hoist(value, key, parent, definition=None, definition_name=None, prop=""):
328328
if not name:
329329
name = value.get("title")
330330
if not name: # don't use default argument to `get` in case prop is empty
331-
name = prop[0].upper() + prop[1:]
331+
name = prop[0].upper() + prop[1:] if prop else definition_name
332332
if name in definitions:
333333
name = f"{name}_{format(hashed & 0xFFFFFFFF, '08x')}"
334334
definitions[name] = value
@@ -338,7 +338,7 @@ def _hoist(value, key, parent, definition=None, definition_name=None, prop=""):
338338
# Recalculate the current definition's hash.
339339
if definition is not None:
340340
hashes[hasher(definition)] = definition_name
341-
# Special case for allOf inheritance (note the `definition` argument). Avoids IndexError when naming.
341+
# Special case for allOf inheritance (note the `definition` argument).
342342
if value is definition and "allOf" in value and len(value) == 1:
343343
for i, v in enumerate(definition["allOf"]):
344344
_hoist(v, i, value["allOf"], v, definition_name, prop)
@@ -359,7 +359,7 @@ def _hoist(value, key, parent, definition=None, definition_name=None, prop=""):
359359

360360
schema.pop(definition_keyword) # avoid re-processing definitions
361361
for key, value in schema.items():
362-
_hoist(value, key, schema)
362+
_hoist(value, key, schema, definition_name="Root")
363363
schema[definition_keyword] = definitions
364364

365365

tests/test_normalize.py

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,27 @@ def test_get_normal_schema_list_traversal():
238238
assert result == [{"type": "string"}, {"type": "integer"}]
239239

240240

241+
def test_hoist_deep_properties_list_traversal():
242+
schema = {
243+
"definitions": {
244+
"Root": {
245+
"anyOf": [
246+
{"title": "Child", "type": "object", "properties": {"x": {"type": "string"}}},
247+
{"type": "null"},
248+
]
249+
}
250+
}
251+
}
252+
hoist_deep_properties(schema, lambda s: s)
253+
254+
assert schema == {
255+
"definitions": {
256+
"Root": {"anyOf": [{"$ref": "#/definitions/Child"}, {"type": "null"}]},
257+
"Child": {"title": "Child", "type": "object", "properties": {"x": {"type": "string"}}},
258+
}
259+
}
260+
261+
241262
@pytest.mark.parametrize("keyword", ["definitions", "$defs"])
242263
def test_hoist_deep_properties_named_by_title(keyword):
243264
schema = {
@@ -280,19 +301,19 @@ def test_hoist_deep_properties_named_by_prop():
280301
def test_hoist_deep_properties_name_collision():
281302
schema = {
282303
"definitions": {
283-
"Child": {"type": "string"}, # name already taken
284304
"Root": {
285305
"type": "object",
286306
"properties": {"child": {"type": "object", "properties": {"x": {"type": "string"}}}},
287307
},
308+
"Child": {"type": "string"}, # name already taken
288309
}
289310
}
290311
hoist_deep_properties(schema, lambda s: s)
291312

292313
assert schema == {
293314
"definitions": {
294-
"Child": {"type": "string"},
295315
"Root": {"type": "object", "properties": {"child": {"$ref": "#/definitions/Child_c018a9ca"}}},
316+
"Child": {"type": "string"},
296317
"Child_c018a9ca": {"type": "object", "properties": {"x": {"type": "string"}}},
297318
}
298319
}
@@ -302,7 +323,29 @@ def test_hoist_deep_properties_top_level_definition():
302323
schema = {"definitions": {"Flat": {"type": "object", "properties": {"x": {"type": "string"}}}}}
303324
hoist_deep_properties(schema, lambda s: s)
304325

305-
assert schema == {"definitions": {"Flat": {"type": "object", "properties": {"x": {"type": "string"}}}}}
326+
assert schema == {
327+
"definitions": {"Flat": {"type": "object", "properties": {"x": {"type": "string"}}}},
328+
}
329+
330+
331+
def test_hoist_deep_properties_top_level_properties():
332+
schema = {"properties": {"top": {"type": "object", "properties": {"x": {"type": "string"}}}}}
333+
hoist_deep_properties(schema, lambda s: s)
334+
335+
assert schema == {
336+
"properties": {"top": {"$ref": "#/$defs/Top"}},
337+
"$defs": {"Top": {"type": "object", "properties": {"x": {"type": "string"}}}},
338+
}
339+
340+
341+
def test_hoist_deep_properties_top_level_applicator():
342+
schema = {"anyOf": [{"type": "object", "properties": {"x": {"type": "string"}}}]}
343+
hoist_deep_properties(schema, lambda s: s)
344+
345+
assert schema == {
346+
"anyOf": [{"$ref": "#/$defs/Root"}],
347+
"$defs": {"Root": {"type": "object", "properties": {"x": {"type": "string"}}}},
348+
}
306349

307350

308351
def test_hoist_deep_properties_allof_special_case():
@@ -328,22 +371,34 @@ def test_hoist_deep_properties_allof_special_case():
328371
}
329372

330373

331-
def test_hoist_deep_properties_top_level_properties():
332-
schema = {"properties": {"foo": {"type": "object", "properties": {"x": {"type": "string"}}}}}
374+
def test_hoist_deep_properties_applicator_allof():
375+
schema = {
376+
"definitions": {
377+
"Root": {
378+
"allOf": [{"type": "object", "properties": {"x": {"type": "string"}}}],
379+
"description": "x",
380+
}
381+
}
382+
}
333383
hoist_deep_properties(schema, lambda s: s)
334384

335385
assert schema == {
336-
"properties": {"foo": {"$ref": "#/$defs/Foo"}},
337-
"$defs": {"Foo": {"type": "object", "properties": {"x": {"type": "string"}}}},
386+
"definitions": {
387+
"Root": {
388+
"allOf": [{"$ref": "#/definitions/Root_c018a9ca"}],
389+
"description": "x",
390+
},
391+
"Root_c018a9ca": {"type": "object", "properties": {"x": {"type": "string"}}},
392+
}
338393
}
339394

340395

341-
def test_hoist_deep_properties_list_traversal():
396+
def test_hoist_deep_properties_applicator_anyof():
342397
schema = {
343398
"definitions": {
344399
"Root": {
345400
"anyOf": [
346-
{"title": "Child", "type": "object", "properties": {"x": {"type": "string"}}},
401+
{"type": "object", "properties": {"x": {"type": "string"}}},
347402
{"type": "null"},
348403
]
349404
}
@@ -353,8 +408,8 @@ def test_hoist_deep_properties_list_traversal():
353408

354409
assert schema == {
355410
"definitions": {
356-
"Root": {"anyOf": [{"$ref": "#/definitions/Child"}, {"type": "null"}]},
357-
"Child": {"title": "Child", "type": "object", "properties": {"x": {"type": "string"}}},
411+
"Root": {"anyOf": [{"$ref": "#/definitions/Root_c018a9ca"}, {"type": "null"}]},
412+
"Root_c018a9ca": {"type": "object", "properties": {"x": {"type": "string"}}},
358413
}
359414
}
360415

0 commit comments

Comments
 (0)