Skip to content

Commit 6a45966

Browse files
p1-alexandrevaneyp1-ra
authored andcommitted
improve collision resolver and resolved schema tests
1 parent b551b04 commit 6a45966

File tree

4 files changed

+202
-5
lines changed

4 files changed

+202
-5
lines changed

openapi_python_client/resolver/collision_resolver.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def _browse_schema(self, attr: Any, root_attr: Any) -> None:
4444
existing_ref.pointer.value != ref.pointer.value
4545
and ref.pointer.tokens()[-1] == existing_ref.pointer.tokens()[-1]
4646
):
47-
print("Found same schema for different pointer")
47+
self._errors.append(f"Found a duplicate schema in {existing_ref.value} and {ref.value}")
4848
else:
4949
self._schema_index[hashed_schema] = ref
5050

@@ -69,7 +69,7 @@ def _get_from_ref(self, ref: Reference, attr: SchemaData) -> SchemaData:
6969
if isinstance(cursor, dict) and key in cursor:
7070
cursor = cursor[key]
7171
else:
72-
print("ERROR")
72+
self._errors.append(f"Did not find data corresponding to the reference {ref.value}")
7373

7474
if list(cursor) == ["$ref"]:
7575
ref2 = Reference(cursor["$ref"], self._parent)

openapi_python_client/resolver/resolved_schema.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def _process(self) -> None:
4141

4242
def _process_remote_paths(self) -> None:
4343
refs_to_replace = []
44+
refs_to_remove = []
4445
for owner, ref_key, ref_val in self._lookup_schema_references_in(self._root, "paths"):
4546
ref = Reference(ref_val, self._parent)
4647

@@ -58,13 +59,17 @@ def _process_remote_paths(self) -> None:
5859
remote_value = self._lookup_dict(remote_schema, tokens)
5960
if not remote_value:
6061
self._errors.append("Failed to read remote value {}, in remote ref {}".format(path, remote_path))
62+
refs_to_remove.append((owner, ref_key))
6163
else:
6264
refs_to_replace.append((owner, remote_schema, remote_value))
6365

6466
for owner, remote_schema, remote_value in refs_to_replace:
6567
self._process_remote_components(remote_schema, remote_value, 1, self._parent)
6668
self._replace_reference_with(owner, remote_value)
6769

70+
for owner, ref_key in refs_to_remove:
71+
owner.pop(ref_key)
72+
6873
def _process_remote_components(
6974
self, owner: SchemaData, subpart: Union[SchemaData, None] = None, depth: int = 0, parent_path: str = None
7075
) -> None:

tests/test_resolver/test_resolver_collision_resolver.py

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,44 @@
55
import pytest
66

77

8+
def test__collision_resolver_get_schema_from_ref():
9+
10+
from openapi_python_client.resolver.collision_resolver import CollisionResolver
11+
12+
root_schema = {"foo": {"$ref": "first_instance.yaml#/foo"}}
13+
14+
external_schemas = {"/home/user/first_instance.yaml": {"food": {"description": "food_first_description"}}}
15+
16+
errors = []
17+
18+
CollisionResolver(root_schema, external_schemas, errors, "/home/user").resolve()
19+
20+
assert len(errors) == 1
21+
assert errors == ["Did not find data corresponding to the reference first_instance.yaml#/foo"]
22+
23+
24+
def test__collision_resolver_duplicate_schema():
25+
26+
from openapi_python_client.resolver.collision_resolver import CollisionResolver
27+
28+
root_schema = {
29+
"foo": {"$ref": "first_instance.yaml#/foo"},
30+
"bar": {"$ref": "second_instance.yaml#/bar/foo"},
31+
}
32+
33+
external_schemas = {
34+
"/home/user/first_instance.yaml": {"foo": {"description": "foo_first_description"}},
35+
"/home/user/second_instance.yaml": {"bar": {"foo": {"description": "foo_first_description"}}},
36+
}
37+
38+
errors = []
39+
40+
CollisionResolver(root_schema, external_schemas, errors, "/home/user").resolve()
41+
42+
assert len(errors) == 1
43+
assert errors == ["Found a duplicate schema in first_instance.yaml#/foo and second_instance.yaml#/bar/foo"]
44+
45+
846
def test__collision_resolver():
947

1048
from openapi_python_client.resolver.collision_resolver import CollisionResolver
@@ -17,6 +55,7 @@ def test__collision_resolver():
1755
"barfoobar": {"$ref": "first_instance.yaml#/bar/foo"},
1856
"localref": {"$ref": "#/local_ref"},
1957
"local_ref": {"description": "a local ref"},
58+
"array": ["array_item_one", "array_item_two"],
2059
"last": {"$ref": "first_instance.yaml#/fourth_instance"},
2160
"baz": {"$ref": "fifth_instance.yaml#/foo"},
2261
}
@@ -27,7 +66,10 @@ def test__collision_resolver():
2766
"bar": {"foo": {"description": "nested foo"}},
2867
"fourth_instance": {"$ref": "fourth_instance.yaml#/foo"},
2968
},
30-
"/home/user/second_instance.yaml": {"foo": {"description": "foo_second_description"}},
69+
"/home/user/second_instance.yaml": {
70+
"foo": {"description": "foo_second_description"},
71+
"another_local_ref": {"$ref": "#/foo"},
72+
},
3173
"/home/user/third_instance.yaml": {"foo": {"description": "foo_third_description"}},
3274
"/home/user/fourth_instance.yaml": {"foo": {"description": "foo_fourth_description"}},
3375
"/home/user/fifth_instance.yaml": {"foo": {"description": "foo_second_description"}},
@@ -41,6 +83,7 @@ def test__collision_resolver():
4183
"barfoobar": {"$ref": "first_instance.yaml#/bar/foo"},
4284
"localref": {"$ref": "#/local_ref"},
4385
"local_ref": {"description": "a local ref"},
86+
"array": ["array_item_one", "array_item_two"],
4487
"last": {"$ref": "first_instance.yaml#/fourth_instance"},
4588
"baz": {"$ref": "fifth_instance.yaml#/foo_2"},
4689
}
@@ -51,7 +94,10 @@ def test__collision_resolver():
5194
"bar": {"foo": {"description": "nested foo"}},
5295
"fourth_instance": {"$ref": "fourth_instance.yaml#/foo_4"},
5396
},
54-
"/home/user/second_instance.yaml": {"foo_2": {"description": "foo_second_description"}},
97+
"/home/user/second_instance.yaml": {
98+
"foo_2": {"description": "foo_second_description"},
99+
"another_local_ref": {"$ref": "#/foo_2"},
100+
},
55101
"/home/user/third_instance.yaml": {"foo_3": {"description": "foo_third_description"}},
56102
"/home/user/fourth_instance.yaml": {"foo_4": {"description": "foo_fourth_description"}},
57103
"/home/user/fifth_instance.yaml": {"foo_2": {"description": "foo_second_description"}},
@@ -64,3 +110,54 @@ def test__collision_resolver():
64110
assert len(errors) == 0
65111
assert root_schema == root_schema_result
66112
assert external_schemas == external_schemas_result
113+
114+
115+
def test__collision_resolver_deep_root_keys():
116+
117+
from openapi_python_client.resolver.collision_resolver import CollisionResolver
118+
119+
root_schema = {
120+
"foobar": {"$ref": "first_instance.yaml#/bar/foo"},
121+
"barfoo": {"$ref": "second_instance.yaml#/bar/foo"},
122+
"barfoobar": {"$ref": "second_instance.yaml#/barfoobar"},
123+
}
124+
125+
external_schemas = {
126+
"/home/user/first_instance.yaml": {
127+
"bar": {"foo": {"description": "foo_first_description"}},
128+
},
129+
"/home/user/second_instance.yaml": {
130+
"bar": {"foo": {"description": "foo_second_description"}},
131+
"barfoobar": {
132+
"type": "object",
133+
"allOf": [{"description": "first_description"}, {"description": "second_description"}],
134+
},
135+
},
136+
}
137+
138+
root_schema_result = {
139+
"foobar": {"$ref": "first_instance.yaml#/bar/foo"},
140+
"barfoo": {"$ref": "second_instance.yaml#/bar/foo_2"},
141+
"barfoobar": {"$ref": "second_instance.yaml#/barfoobar"},
142+
}
143+
144+
external_schemas_result = {
145+
"/home/user/first_instance.yaml": {
146+
"bar": {"foo": {"description": "foo_first_description"}},
147+
},
148+
"/home/user/second_instance.yaml": {
149+
"bar": {"foo_2": {"description": "foo_second_description"}},
150+
"barfoobar": {
151+
"type": "object",
152+
"allOf": [{"description": "first_description"}, {"description": "second_description"}],
153+
},
154+
},
155+
}
156+
157+
errors = []
158+
159+
CollisionResolver(root_schema, external_schemas, errors, "/home/user").resolve()
160+
161+
assert len(errors) == 0
162+
assert root_schema == root_schema_result
163+
assert external_schemas == external_schemas_result

tests/test_resolver/test_resolver_resolved_schema.py

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ def test__resolved_schema_with_resolved_external_references():
1010
from openapi_python_client.resolver.resolved_schema import ResolvedSchema
1111

1212
root_schema = {"foobar": {"$ref": "foobar.yaml#/foo"}}
13-
external_schemas = {"/home/user/foobar.yaml": {"foo": {"description": "foobar_description"}}}
13+
14+
external_schemas = {
15+
"/home/user/foobar.yaml": {"foo": {"$ref": "/home/user/foobar_2.yaml#/foo"}},
16+
"/home/user/foobar_2.yaml": {"foo": {"description": "foobar_description"}},
17+
}
1418
errors = []
1519

1620
resolved_schema = ResolvedSchema(root_schema, external_schemas, errors, "/home/user").schema
@@ -24,6 +28,97 @@ def test__resolved_schema_with_resolved_external_references():
2428
assert "foobar_description" in resolved_schema["foo"]["description"]
2529

2630

31+
def test__resolved_schema_with_duplicate_ref():
32+
33+
from openapi_python_client.resolver.resolved_schema import ResolvedSchema
34+
35+
root_schema = {
36+
"foo": {"$ref": "foobar.yaml#/foo"},
37+
"bar": {"$ref": "foobar.yaml#/foo"},
38+
"list": [{"foobar": {"$ref": "foobar.yaml#/bar"}}, {"barfoo": {"$ref": "foobar.yaml#/bar2/foo"}}],
39+
}
40+
41+
external_schemas = {
42+
"/home/user/foobar.yaml": {
43+
"foo": {"description": "foo_description"},
44+
"bar": {"$ref": "#/foo"},
45+
"bar2": {"foo": {"description": "foo_second_description"}},
46+
},
47+
}
48+
49+
errors = []
50+
51+
resolved_schema = ResolvedSchema(root_schema, external_schemas, errors, "/home/user").schema
52+
53+
assert len(errors) == 0
54+
55+
56+
def test__resolved_schema_with_malformed_schema():
57+
58+
from openapi_python_client.resolver.resolved_schema import ResolvedSchema
59+
60+
root_schema = {
61+
"paths": {
62+
"/foo/bar": {"$ref": "inexistant.yaml#/paths/~1foo~1bar"},
63+
"/bar": {"$ref": "foobar.yaml#/paths/~1bar"},
64+
},
65+
"foo": {"$ref": "inexistant.yaml#/foo"},
66+
}
67+
68+
external_schemas = {
69+
"/home/user/foobar.yaml": {
70+
"paths": {
71+
"/foo/bar": {"description": "foobar_description"},
72+
},
73+
},
74+
}
75+
76+
errors = []
77+
78+
resolved_schema = ResolvedSchema(root_schema, external_schemas, errors, "/home/user").schema
79+
80+
assert len(errors) == 4
81+
assert errors == [
82+
"Failed to resolve remote reference > /home/user/inexistant.yaml",
83+
"Failed to read remote value /paths//bar, in remote ref /home/user/foobar.yaml",
84+
"Failed to resolve remote reference > /home/user/inexistant.yaml",
85+
"Failed to resolve remote reference > /home/user/inexistant.yaml",
86+
]
87+
88+
89+
def test__resolved_schema_with_remote_paths():
90+
91+
from openapi_python_client.resolver.resolved_schema import ResolvedSchema
92+
93+
root_schema = {
94+
"paths": {
95+
"/foo/bar": {"$ref": "foobar.yaml#/paths/~1foo~1bar"},
96+
"/foo/bar2": {"$ref": "#/bar2"},
97+
},
98+
"bar2": {"description": "bar2_description"},
99+
}
100+
101+
external_schemas = {
102+
"/home/user/foobar.yaml": {
103+
"paths": {
104+
"/foo/bar": {"description": "foobar_description"},
105+
},
106+
},
107+
}
108+
109+
expected_result = {
110+
"paths": {"/foo/bar": {"description": "foobar_description"}, "/foo/bar2": {"$ref": "#/bar2"}},
111+
"bar2": {"description": "bar2_description"},
112+
}
113+
114+
errors = []
115+
116+
resolved_schema = ResolvedSchema(root_schema, external_schemas, errors, "/home/user").schema
117+
118+
assert len(errors) == 0
119+
assert resolved_schema == expected_result
120+
121+
27122
def test__resolved_schema_with_absolute_paths():
28123

29124
from openapi_python_client.resolver.resolved_schema import ResolvedSchema

0 commit comments

Comments
 (0)