Skip to content

Commit a3f8fa8

Browse files
committed
refactor: More test cleanup for ModelProperty
1 parent 9600afc commit a3f8fa8

File tree

3 files changed

+169
-151
lines changed

3 files changed

+169
-151
lines changed

mypy.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[mypy]
2+
plugins = pydantic.mypy
23
disallow_any_generics = True
34
disallow_untyped_defs = True
45
warn_redundant_casts = True

openapi_python_client/parser/properties/model_property.py

+31-21
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,31 @@ def _process_properties(*, data: oai.Schema, schemas: Schemas, class_name: str)
104104
)
105105

106106

107+
def _get_additional_properties(
108+
*, schema_additional: Union[None, bool, oai.Reference, oai.Schema], schemas: Schemas, class_name: str
109+
) -> Tuple[Union[bool, Property, PropertyError], Schemas]:
110+
from . import property_from_data
111+
112+
if schema_additional is None:
113+
return True, schemas
114+
115+
if isinstance(schema_additional, bool):
116+
return schema_additional, schemas
117+
118+
if isinstance(schema_additional, oai.Schema) and not any(schema_additional.dict().values()):
119+
# An empty schema
120+
return True, schemas
121+
122+
additional_properties, schemas = property_from_data(
123+
name="AdditionalProperty",
124+
required=True, # in the sense that if present in the dict will not be None
125+
data=schema_additional,
126+
schemas=schemas,
127+
parent_name=class_name,
128+
)
129+
return additional_properties, schemas
130+
131+
107132
def build_model_property(
108133
*, data: oai.Schema, name: str, schemas: Schemas, required: bool, parent_name: Optional[str]
109134
) -> Tuple[Union[ModelProperty, PropertyError], Schemas]:
@@ -118,8 +143,6 @@ def build_model_property(
118143
required: Whether or not this property is required by the parent (affects typing)
119144
parent_name: The name of the property that this property is inside of (affects class naming)
120145
"""
121-
from . import property_from_data
122-
123146
class_name = data.title or name
124147
if parent_name:
125148
class_name = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_name)}"
@@ -130,26 +153,13 @@ def build_model_property(
130153
return property_data, schemas
131154
schemas = property_data.schemas
132155

133-
additional_properties: Union[bool, Property, PropertyError]
134-
if data.additionalProperties is None:
135-
additional_properties = True
136-
elif isinstance(data.additionalProperties, bool):
137-
additional_properties = data.additionalProperties
138-
elif isinstance(data.additionalProperties, oai.Schema) and not any(data.additionalProperties.dict().values()):
139-
# An empty schema
140-
additional_properties = True
141-
else:
142-
assert isinstance(data.additionalProperties, (oai.Schema, oai.Reference))
143-
additional_properties, schemas = property_from_data(
144-
name="AdditionalProperty",
145-
required=True, # in the sense that if present in the dict will not be None
146-
data=data.additionalProperties,
147-
schemas=schemas,
148-
parent_name=class_name,
149-
)
150-
if isinstance(additional_properties, PropertyError):
151-
return additional_properties, schemas
156+
additional_properties, schemas = _get_additional_properties(
157+
schema_additional=data.additionalProperties, schemas=schemas, class_name=class_name
158+
)
159+
if isinstance(additional_properties, Property):
152160
property_data.relative_imports.update(additional_properties.get_imports(prefix=".."))
161+
elif isinstance(additional_properties, PropertyError):
162+
return additional_properties, schemas
153163

154164
prop = ModelProperty(
155165
reference=ref,

tests/test_parser/test_properties/test_model_property.py

+137-130
Original file line numberDiff line numberDiff line change
@@ -64,134 +64,141 @@ def test_get_imports():
6464
}
6565

6666

67-
@pytest.mark.parametrize(
68-
"additional_properties_schema, expected_additional_properties",
69-
[
70-
(True, True),
71-
(oai.Schema.construct(), True),
72-
(None, True),
73-
(False, False),
74-
(
75-
oai.Schema.construct(type="string"),
76-
StringProperty(name="AdditionalProperty", required=True, nullable=False, default=None),
77-
),
78-
],
79-
)
80-
def test_build_model_property(additional_properties_schema, expected_additional_properties):
81-
from openapi_python_client.parser.properties import Schemas, build_model_property
82-
83-
data = oai.Schema.construct(
84-
required=["req"],
85-
title="MyModel",
86-
properties={
87-
"req": oai.Schema.construct(type="string"),
88-
"opt": oai.Schema(type="string", format="date-time"),
89-
},
90-
description="A class called MyModel",
91-
nullable=False,
92-
additionalProperties=additional_properties_schema,
93-
)
94-
schemas = Schemas(models={"OtherModel": None})
95-
96-
model, new_schemas = build_model_property(
97-
data=data,
98-
name="prop",
99-
schemas=schemas,
100-
required=True,
101-
parent_name="parent",
102-
)
103-
104-
assert new_schemas != schemas
105-
assert new_schemas.models == {
106-
"OtherModel": None,
107-
"ParentMyModel": model,
108-
}
109-
assert model == ModelProperty(
110-
name="prop",
111-
required=True,
112-
nullable=False,
113-
default=None,
114-
reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"),
115-
required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)],
116-
optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)],
117-
description=data.description,
118-
relative_imports={
119-
"from dateutil.parser import isoparse",
120-
"from typing import cast",
121-
"import datetime",
122-
"from ..types import UNSET, Unset",
123-
"from typing import Union",
124-
},
125-
additional_properties=expected_additional_properties,
126-
)
127-
128-
129-
def test_build_model_property_conflict():
130-
from openapi_python_client.parser.properties import Schemas, build_model_property
131-
132-
data = oai.Schema.construct(
133-
required=["req"],
134-
properties={
135-
"req": oai.Schema.construct(type="string"),
136-
"opt": oai.Schema(type="string", format="date-time"),
137-
},
138-
nullable=False,
139-
)
140-
schemas = Schemas(models={"OtherModel": None})
141-
142-
err, new_schemas = build_model_property(
143-
data=data,
144-
name="OtherModel",
145-
schemas=schemas,
146-
required=True,
147-
parent_name=None,
67+
class TestBuildModelProperty:
68+
@pytest.mark.parametrize(
69+
"additional_properties_schema, expected_additional_properties",
70+
[
71+
(True, True),
72+
(oai.Schema.construct(), True),
73+
(None, True),
74+
(False, False),
75+
(
76+
oai.Schema.construct(type="string"),
77+
StringProperty(name="AdditionalProperty", required=True, nullable=False, default=None),
78+
),
79+
],
14880
)
149-
150-
assert new_schemas == schemas
151-
assert err == PropertyError(detail='Attempted to generate duplicate models with name "OtherModel"', data=data)
152-
153-
154-
def test_build_model_property_bad_prop():
155-
from openapi_python_client.parser.properties import Schemas, build_model_property
156-
157-
data = oai.Schema(
158-
properties={
159-
"bad": oai.Schema(type="not_real"),
160-
},
161-
)
162-
schemas = Schemas(models={"OtherModel": None})
163-
164-
err, new_schemas = build_model_property(
165-
data=data,
166-
name="prop",
167-
schemas=schemas,
168-
required=True,
169-
parent_name=None,
170-
)
171-
172-
assert new_schemas == schemas
173-
assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
174-
175-
176-
def test_build_model_property_bad_additional_props():
177-
from openapi_python_client.parser.properties import Schemas, build_model_property
178-
179-
additional_properties = oai.Schema(
180-
type="object",
181-
properties={
182-
"bad": oai.Schema(type="not_real"),
183-
},
184-
)
185-
data = oai.Schema(additionalProperties=additional_properties)
186-
schemas = Schemas(models={"OtherModel": None})
187-
188-
err, new_schemas = build_model_property(
189-
data=data,
190-
name="prop",
191-
schemas=schemas,
192-
required=True,
193-
parent_name=None,
194-
)
195-
196-
assert new_schemas == schemas
197-
assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
81+
def test_additional_schemas(self, additional_properties_schema, expected_additional_properties):
82+
from openapi_python_client.parser.properties import Schemas, build_model_property
83+
84+
data = oai.Schema.construct(
85+
additionalProperties=additional_properties_schema,
86+
)
87+
88+
model, _ = build_model_property(
89+
data=data,
90+
name="prop",
91+
schemas=Schemas(),
92+
required=True,
93+
parent_name="parent",
94+
)
95+
96+
assert model.additional_properties == expected_additional_properties
97+
98+
def test_happy_path(self):
99+
from openapi_python_client.parser.properties import Schemas, build_model_property
100+
101+
data = oai.Schema.construct(
102+
required=["req"],
103+
title="MyModel",
104+
properties={
105+
"req": oai.Schema.construct(type="string"),
106+
"opt": oai.Schema(type="string", format="date-time"),
107+
},
108+
description="A class called MyModel",
109+
nullable=False,
110+
)
111+
schemas = Schemas(models={"OtherModel": None})
112+
113+
model, new_schemas = build_model_property(
114+
data=data,
115+
name="prop",
116+
schemas=schemas,
117+
required=True,
118+
parent_name="parent",
119+
)
120+
121+
assert new_schemas != schemas
122+
assert new_schemas.models == {
123+
"OtherModel": None,
124+
"ParentMyModel": model,
125+
}
126+
assert model == ModelProperty(
127+
name="prop",
128+
required=True,
129+
nullable=False,
130+
default=None,
131+
reference=Reference(class_name="ParentMyModel", module_name="parent_my_model"),
132+
required_properties=[StringProperty(name="req", required=True, nullable=False, default=None)],
133+
optional_properties=[DateTimeProperty(name="opt", required=False, nullable=False, default=None)],
134+
description=data.description,
135+
relative_imports={
136+
"from dateutil.parser import isoparse",
137+
"from typing import cast",
138+
"import datetime",
139+
"from ..types import UNSET, Unset",
140+
"from typing import Union",
141+
},
142+
additional_properties=True,
143+
)
144+
145+
def test_model_name_conflict(self):
146+
from openapi_python_client.parser.properties import Schemas, build_model_property
147+
148+
data = oai.Schema.construct()
149+
schemas = Schemas(models={"OtherModel": None})
150+
151+
err, new_schemas = build_model_property(
152+
data=data,
153+
name="OtherModel",
154+
schemas=schemas,
155+
required=True,
156+
parent_name=None,
157+
)
158+
159+
assert new_schemas == schemas
160+
assert err == PropertyError(detail='Attempted to generate duplicate models with name "OtherModel"', data=data)
161+
162+
def test_bad_props_return_error(self):
163+
from openapi_python_client.parser.properties import Schemas, build_model_property
164+
165+
data = oai.Schema(
166+
properties={
167+
"bad": oai.Schema(type="not_real"),
168+
},
169+
)
170+
schemas = Schemas()
171+
172+
err, new_schemas = build_model_property(
173+
data=data,
174+
name="prop",
175+
schemas=schemas,
176+
required=True,
177+
parent_name=None,
178+
)
179+
180+
assert new_schemas == schemas
181+
assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
182+
183+
def test_bad_additional_props_return_error(self):
184+
from openapi_python_client.parser.properties import Schemas, build_model_property
185+
186+
additional_properties = oai.Schema(
187+
type="object",
188+
properties={
189+
"bad": oai.Schema(type="not_real"),
190+
},
191+
)
192+
data = oai.Schema(additionalProperties=additional_properties)
193+
schemas = Schemas()
194+
195+
err, new_schemas = build_model_property(
196+
data=data,
197+
name="prop",
198+
schemas=schemas,
199+
required=True,
200+
parent_name=None,
201+
)
202+
203+
assert new_schemas == schemas
204+
assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))

0 commit comments

Comments
 (0)