Skip to content

Commit a6deec7

Browse files
committed
:feat: Added check for references and lists, to properly type self references
1 parent 0ef4e9d commit a6deec7

File tree

6 files changed

+63
-16
lines changed

6 files changed

+63
-16
lines changed

poetry.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "openapi-python-generator"
3-
version = "0.4.0"
3+
version = "0.4.1"
44
description = "Openapi Python Generator"
55
authors = ["Marco Müllner <[email protected]>"]
66
license = "MIT"

src/openapi_python_generator/language_converters/python/model_generator.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from openapi_python_generator.models import TypeConversion
2222

2323

24-
def type_converter(schema: Schema, model_name: str | None = None, required: bool = False) -> TypeConversion:
24+
def type_converter(schema: Schema, required: bool = False, model_name: str | None = None,) -> TypeConversion:
2525
"""
2626
Converts an OpenAPI type to a Python type.
2727
:param schema: Schema containing the type to be converted
@@ -131,10 +131,10 @@ def type_converter(schema: Schema, model_name: str | None = None, required: bool
131131
elif schema.type == "array":
132132
retVal = pre_type + "List["
133133
if isinstance(schema.items, Reference):
134-
import_type = schema.items.ref.split("/")[-1]
135-
import_types = [f"from .{import_type} import {import_type}"]
136-
original_type = "array<" + schema.items.ref.split("/")[-1] + ">"
137-
retVal += schema.items.ref.split("/")[-1]
134+
converted_reference = _generate_property_from_reference(model_name, "", schema.items, schema)
135+
import_types = converted_reference.type.import_types
136+
original_type = "array<" + converted_reference.type.original_type + ">"
137+
retVal += converted_reference.type.converted_type
138138
elif isinstance(schema.items, Schema):
139139
original_type = "array<" + str(schema.items.type) + ">"
140140
retVal += type_converter(schema.items, True).converted_type
@@ -176,14 +176,14 @@ def _generate_property_from_schema(
176176
)
177177
return Property(
178178
name=name,
179-
type=type_converter(schema, model_name, required),
179+
type=type_converter(schema, required, model_name),
180180
required=required,
181181
default=None if required else "None",
182182
)
183183

184184

185185
def _generate_property_from_reference(
186-
name: str, reference: Reference, parent_schema: Optional[Schema] = None
186+
model_name: str, name: str, reference: Reference, parent_schema: Optional[Schema] = None,
187187
) -> Property:
188188
"""
189189
Generates a property from a reference. It takes the name of the reference as the type, and then
@@ -200,11 +200,18 @@ def _generate_property_from_reference(
200200
)
201201
import_model = reference.ref.split("/")[-1]
202202

203-
type_conv = TypeConversion(
204-
original_type=reference.ref,
205-
converted_type=import_model if required else "Optional[" + import_model + "]",
206-
import_types=[f"from .{import_model} import {import_model}"],
207-
)
203+
if import_model == model_name:
204+
type_conv = TypeConversion(
205+
original_type=reference.ref,
206+
converted_type=import_model if required else 'Optional["' + import_model + '"]',
207+
import_types=None
208+
)
209+
else:
210+
type_conv = TypeConversion(
211+
original_type=reference.ref,
212+
converted_type=import_model if required else "Optional[" + import_model + "]",
213+
import_types=[f"from .{import_model} import {import_model}"],
214+
)
208215
return Property(
209216
name=name,
210217
type=type_conv,
@@ -261,7 +268,7 @@ def generate_models(components: Components) -> List[Model]:
261268
for prop_name, property in property_iterator:
262269
if isinstance(property, Reference):
263270
conv_property = _generate_property_from_reference(
264-
prop_name, property, schema_or_reference
271+
name, prop_name, property, schema_or_reference
265272
)
266273
else:
267274
conv_property = _generate_property_from_schema(

src/openapi_python_generator/language_converters/python/templates/models.jinja2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ class {{ schema_name }}(BaseModel):
1818
"""
1919
{% for property in properties %}
2020

21-
{{ property.name | replace("@","")}} : {{ property.type.converted_type }} = Field(alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %})
21+
{{ property.name | replace("@","")}} : {{ property.type.converted_type | safe }} = Field(alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %})
2222
{% endfor %}

tests/regression/test_issue_9.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pytest
2+
from click.testing import CliRunner
3+
4+
from openapi_python_generator.__main__ import main
5+
from openapi_python_generator.common import HTTPLibrary
6+
from tests.conftest import test_data_folder
7+
from tests.conftest import test_result_path
8+
9+
10+
@pytest.fixture
11+
def runner() -> CliRunner:
12+
"""Fixture for invoking command-line interfaces."""
13+
return CliRunner()
14+
15+
@pytest.mark.parametrize(
16+
"library",
17+
[HTTPLibrary.httpx, HTTPLibrary.requests, HTTPLibrary.aiohttp],
18+
)
19+
def test_issue_11(runner: CliRunner, model_data_with_cleanup, library) -> None:
20+
"""
21+
https://github.com/MarcoMuellner/openapi-python-generator/issues/7
22+
"""
23+
result = runner.invoke(
24+
main,
25+
[
26+
str(test_data_folder / "openapi_gitea_converted.json"),
27+
str(test_result_path),
28+
"--library",
29+
library.value,
30+
],
31+
)
32+
assert result.exit_code == 0
33+
34+
exec(
35+
f"import {test_result_path.name}",
36+
globals(),
37+
locals(),
38+
)
39+

tests/test_data/gitea_issue_11.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)