Skip to content

Commit 97063d5

Browse files
Fix tests
1 parent b33df4d commit 97063d5

File tree

6 files changed

+167
-13
lines changed

6 files changed

+167
-13
lines changed

openapi_python_client/parser/properties/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,6 @@ def _property_from_data(
482482
)
483483
if data.anyOf or data.oneOf:
484484
return build_union_property(data=data, name=name, required=required, schemas=schemas, parent_name=parent_name)
485-
486485
if data.type == "string":
487486
return _string_based_property(name=name, required=required, data=data), schemas
488487
elif data.type == "number":
@@ -587,5 +586,6 @@ def build_schemas(*, components: Dict[str, Union[oai.Reference, oai.Schema]]) ->
587586
else:
588587
schemas = schemas_or_err
589588

589+
schemas.errors.extend(errors)
590590
schemas.errors.extend(resolve_errors)
591591
return schemas

openapi_python_client/parser/properties/model_property.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class ModelProperty(Property):
2020

2121
reference: Reference
2222
references: List[oai.Reference]
23-
2423
required_properties: List[Property]
2524
optional_properties: List[Property]
2625
description: str

openapi_python_client/templates/endpoint_macros.pyi

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ params: Dict[str, Any] = {
3333
}
3434
{% for property in endpoint.query_parameters %}
3535
{% if not property.required or property.nullable %}
36-
if {% if not property.required %}{{ property.python_name }} is not UNSET and {% endif %}{{ property.python_name }} is not None:
37-
{% if property.template %}
38-
params["{{ property.name }}"] = {{ "json_" + property.python_name }}
36+
{% set property_name = "json_" + property.python_name if property.template else property.python_name %}
37+
if {% if not property.required %}not isinstance({{ property_name }}, Unset) and {% endif %}{{ property_name }} is not None:
38+
{% if property.json_is_dict %}
39+
params.update({{ property_name }})
3940
{% else %}
40-
params["{{ property.name }}"] = {{ property.python_name }}
41+
params["{{ property.name }}"] = {{ property_name }}
4142
{% endif %}
4243
{% endif %}
4344
{% endfor %}

openapi_python_client/templates/property_templates/model_property.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{% macro construct(property, source, initial_value=None) %}
2-
{% if property.required %}
2+
{% if property.required and not property.nullable %}
33
{{ property.python_name }} = {{ property.reference.class_name }}.from_dict({{ source }})
44
{% else %}
55
{% if initial_value != None %}
@@ -10,7 +10,7 @@
1010
{{ property.python_name }}: {{ property.get_type_string() }} = UNSET
1111
{% endif %}
1212
_{{ property.python_name }} = {{source}}
13-
if _{{ property.python_name }} is not None and not isinstance(_{{ property.python_name }}, Unset):
13+
if {% if property.nullable %}_{{ property.python_name }} is not None{% endif %}{% if property.nullable and not property.required %} and {% endif %}{% if not property.required %}not isinstance(_{{ property.python_name }}, Unset){% endif %}:
1414
{{ property.python_name }} = {{ property.reference.class_name }}.from_dict(cast(Dict[str, Any], _{{ property.python_name }}))
1515
{% endif %}
1616
{% endmacro %}

tests/test_parser/test_properties/test_init.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,7 @@ def test_property_from_data_ref_model(self):
584584
nullable=False,
585585
default=None,
586586
reference=Reference(class_name=class_name, module_name="my_model"),
587+
references=[],
587588
required_properties=[],
588589
optional_properties=[],
589590
description="",
@@ -600,6 +601,7 @@ def test_property_from_data_ref_model(self):
600601
nullable=False,
601602
default=None,
602603
reference=Reference(class_name=class_name, module_name="my_model"),
604+
references=[],
603605
required_properties=[],
604606
optional_properties=[],
605607
description="",
@@ -990,15 +992,20 @@ def test_build_schemas(mocker):
990992
schemas_1 = mocker.MagicMock()
991993
model_2 = mocker.MagicMock()
992994
schemas_2 = mocker.MagicMock(errors=[])
993-
error = PropertyError()
995+
schemas_2.models = {"1": model_1, "2": model_2}
996+
error_1 = PropertyError()
994997
schemas_3 = mocker.MagicMock()
998+
schemas_4 = mocker.MagicMock(errors=[])
999+
model_1.resolve_references.return_value = schemas_4
1000+
error_2 = PropertyError()
1001+
model_2.resolve_references.return_value = error_2
9951002

9961003
# This loops through one for each, then again to retry the error
9971004
build_model_property.side_effect = [
9981005
(model_1, schemas_1),
9991006
(model_2, schemas_2),
1000-
(error, schemas_3),
1001-
(error, schemas_3),
1007+
(error_1, schemas_3),
1008+
(error_1, schemas_3),
10021009
]
10031010

10041011
from openapi_python_client.parser.properties import Schemas, build_schemas
@@ -1014,8 +1021,12 @@ def test_build_schemas(mocker):
10141021
]
10151022
)
10161023
# schemas_3 was the last to come back from build_model_property, but it should be ignored because it's an error
1017-
assert result == schemas_2
1018-
assert result.errors == [error]
1024+
model_1.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_2)
1025+
# schemas_4 came from resolving model_1
1026+
model_2.resolve_references.assert_called_once_with(components=in_data, schemas=schemas_4)
1027+
# resolving model_2 resulted in err, so no schemas_5
1028+
assert result == schemas_4
1029+
assert result.errors == [error_1, error_2]
10191030

10201031

10211032
def test_build_parse_error_on_reference():
@@ -1089,6 +1100,7 @@ def test_build_model_property(additional_properties_schema, expected_additional_
10891100
nullable=False,
10901101
default=None,
10911102
reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"),
1103+
references=[],
10921104
required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)],
10931105
optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)],
10941106
description=data.description,

tests/test_parser/test_properties/test_model_property.py

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def test_get_type_string(no_optional, nullable, required, expected):
2323
nullable=nullable,
2424
default=None,
2525
reference=Reference(class_name="MyClass", module_name="my_module"),
26+
references=[],
2627
description="",
2728
optional_properties=[],
2829
required_properties=[],
@@ -42,6 +43,7 @@ def test_get_imports():
4243
nullable=True,
4344
default=None,
4445
reference=Reference(class_name="MyClass", module_name="my_module"),
46+
references=[],
4547
description="",
4648
optional_properties=[],
4749
required_properties=[],
@@ -57,3 +59,143 @@ def test_get_imports():
5759
"from typing import Dict",
5860
"from typing import cast",
5961
}
62+
63+
64+
def test_resolve_references(mocker):
65+
import openapi_python_client.schema as oai
66+
from openapi_python_client.parser.properties import build_model_property
67+
68+
schemas = {
69+
"RefA": oai.Schema.construct(
70+
title=mocker.MagicMock(),
71+
description=mocker.MagicMock(),
72+
required=["String"],
73+
properties={
74+
"String": oai.Schema.construct(type="string"),
75+
"Enum": oai.Schema.construct(type="string", enum=["aValue"]),
76+
"DateTime": oai.Schema.construct(type="string", format="date-time"),
77+
},
78+
),
79+
"RefB": oai.Schema.construct(
80+
title=mocker.MagicMock(),
81+
description=mocker.MagicMock(),
82+
required=["DateTime"],
83+
properties={
84+
"Int": oai.Schema.construct(type="integer"),
85+
"DateTime": oai.Schema.construct(type="string", format="date-time"),
86+
"Float": oai.Schema.construct(type="number", format="float"),
87+
},
88+
),
89+
# Intentionally no properties defined
90+
"RefC": oai.Schema.construct(
91+
title=mocker.MagicMock(),
92+
description=mocker.MagicMock(),
93+
),
94+
}
95+
96+
model_schema = oai.Schema.construct(
97+
allOf=[
98+
oai.Reference.construct(ref="#/components/schemas/RefA"),
99+
oai.Reference.construct(ref="#/components/schemas/RefB"),
100+
oai.Reference.construct(ref="#/components/schemas/RefC"),
101+
oai.Schema.construct(
102+
title=mocker.MagicMock(),
103+
description=mocker.MagicMock(),
104+
required=["Float"],
105+
properties={
106+
"String": oai.Schema.construct(type="string"),
107+
"Float": oai.Schema.construct(type="number", format="float"),
108+
},
109+
),
110+
]
111+
)
112+
113+
components = {**schemas, "Model": model_schema}
114+
115+
from openapi_python_client.parser.properties import Schemas
116+
117+
schemas_holder = Schemas()
118+
model, schemas_holder = build_model_property(
119+
data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None
120+
)
121+
model.resolve_references(components, schemas_holder)
122+
assert sorted(p.name for p in model.required_properties) == ["DateTime", "Float", "String"]
123+
assert all(p.required for p in model.required_properties)
124+
assert sorted(p.name for p in model.optional_properties) == ["Enum", "Int"]
125+
assert all(not p.required for p in model.optional_properties)
126+
127+
128+
def test_resolve_references_nested_allof(mocker):
129+
import openapi_python_client.schema as oai
130+
from openapi_python_client.parser.properties import build_model_property
131+
132+
schemas = {
133+
"RefA": oai.Schema.construct(
134+
title=mocker.MagicMock(),
135+
description=mocker.MagicMock(),
136+
required=["String"],
137+
properties={
138+
"String": oai.Schema.construct(type="string"),
139+
"Enum": oai.Schema.construct(type="string", enum=["aValue"]),
140+
"DateTime": oai.Schema.construct(type="string", format="date-time"),
141+
},
142+
),
143+
"RefB": oai.Schema.construct(
144+
title=mocker.MagicMock(),
145+
description=mocker.MagicMock(),
146+
required=["DateTime"],
147+
properties={
148+
"Int": oai.Schema.construct(type="integer"),
149+
"DateTime": oai.Schema.construct(type="string", format="date-time"),
150+
"Float": oai.Schema.construct(type="number", format="float"),
151+
},
152+
),
153+
# Intentionally no properties defined
154+
"RefC": oai.Schema.construct(
155+
title=mocker.MagicMock(),
156+
description=mocker.MagicMock(),
157+
),
158+
}
159+
160+
model_schema = oai.Schema.construct(
161+
type="object",
162+
properties={
163+
"Key": oai.Schema.construct(
164+
allOf=[
165+
oai.Reference.construct(ref="#/components/schemas/RefA"),
166+
oai.Reference.construct(ref="#/components/schemas/RefB"),
167+
oai.Reference.construct(ref="#/components/schemas/RefC"),
168+
oai.Schema.construct(
169+
title=mocker.MagicMock(),
170+
description=mocker.MagicMock(),
171+
required=["Float"],
172+
properties={
173+
"String": oai.Schema.construct(type="string"),
174+
"Float": oai.Schema.construct(type="number", format="float"),
175+
},
176+
),
177+
]
178+
),
179+
},
180+
)
181+
182+
components = {**schemas, "Model": model_schema}
183+
184+
from openapi_python_client.parser.properties import ModelProperty, Schemas
185+
186+
schemas_holder = Schemas()
187+
model, schemas_holder = build_model_property(
188+
data=model_schema, name="Model", required=True, schemas=schemas_holder, parent_name=None
189+
)
190+
model.resolve_references(components, schemas_holder)
191+
assert sorted(p.name for p in model.required_properties) == []
192+
assert sorted(p.name for p in model.optional_properties) == ["Key"]
193+
assert all(not p.required for p in model.optional_properties)
194+
195+
key_property = model.optional_properties[0]
196+
assert isinstance(key_property, ModelProperty)
197+
key_property.resolve_references(components, schemas_holder)
198+
assert sorted(p.name for p in key_property.required_properties) == ["DateTime", "Float", "String"]
199+
assert all(p.required for p in key_property.required_properties)
200+
assert sorted(p.name for p in key_property.optional_properties) == ["Enum", "Int"]
201+
assert all(not p.required for p in key_property.optional_properties)

0 commit comments

Comments
 (0)