Skip to content

Commit b16ed73

Browse files
emanndbanty
authored andcommitted
Added support for enum schemas (#122)
* Added support for enum schemas. Closes #102 Co-authored-by: Ethan Mann <emann@triaxtec.com>
1 parent 9042dc3 commit b16ed73

File tree

13 files changed

+107
-47
lines changed

13 files changed

+107
-47
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
### Additions
1414
- The generator can now handle many more errors gracefully, skipping the things it can't generate and continuing
1515
with the pieces it can.
16+
- Support for Enums declared in "components/schemas" and references to them. (#120)
1617

1718
### Internal Changes
1819
- Switched OpenAPI document parsing to use Pydantic based on a vendored version of
1920
[openapi-schema-pydantic](https://github.com/kuimono/openapi-schema-pydantic/) (#103).
21+
- Tests can now be run on Windows.
2022

2123

2224

end_to_end_tests/fastapi_app/openapi.json

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@
4141
"title": "An Enum Value",
4242
"type": "array",
4343
"items": {
44-
"enum": [
45-
"FIRST_VALUE",
46-
"SECOND_VALUE"
47-
]
44+
"$ref": "#/components/schemas/AnEnum"
4845
}
4946
},
5047
"name": "an_enum_value",
@@ -150,22 +147,15 @@
150147
"type": "object",
151148
"properties": {
152149
"an_enum_value": {
153-
"title": "An Enum Value",
154-
"enum": [
155-
"FIRST_VALUE",
156-
"SECOND_VALUE"
157-
]
150+
"$ref": "#/components/schemas/AnEnum"
158151
},
159152
"nested_list_of_enums": {
160153
"title": "Nested List Of Enums",
161154
"type": "array",
162155
"items": {
163156
"type": "array",
164157
"items": {
165-
"enum": [
166-
"DIFFERENT",
167-
"OTHER"
168-
]
158+
"$ref": "#/components/schemas/DifferentEnum"
169159
}
170160
},
171161
"default": []
@@ -199,6 +189,14 @@
199189
},
200190
"description": "A Model for testing all the ways custom objects can be used "
201191
},
192+
"AnEnum": {
193+
"title": "AnEnum",
194+
"enum": [
195+
"FIRST_VALUE",
196+
"SECOND_VALUE"
197+
],
198+
"description": "For testing Enums in all the ways they can be used "
199+
},
202200
"Body_upload_file_tests_upload_post": {
203201
"title": "Body_upload_file_tests_upload_post",
204202
"required": [
@@ -213,6 +211,14 @@
213211
}
214212
}
215213
},
214+
"DifferentEnum": {
215+
"title": "DifferentEnum",
216+
"enum": [
217+
"DIFFERENT",
218+
"OTHER"
219+
],
220+
"description": "An enumeration."
221+
},
216222
"HTTPValidationError": {
217223
"title": "HTTPValidationError",
218224
"type": "object",

end_to_end_tests/golden-master/my_test_api_client/api/users.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from ..client import AuthenticatedClient, Client
88
from ..errors import ApiResponseError
99
from ..models.a_model import AModel
10-
from ..models.an_enum_value import AnEnumValue
10+
from ..models.an_enum import AnEnum
1111
from ..models.body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost
1212
from ..models.http_validation_error import HTTPValidationError
1313

1414

1515
def get_user_list(
16-
*, client: Client, an_enum_value: List[AnEnumValue], some_date: Union[date, datetime],
16+
*, client: Client, an_enum_value: List[AnEnum], some_date: Union[date, datetime],
1717
) -> Union[
1818
List[AModel], HTTPValidationError,
1919
]:

end_to_end_tests/golden-master/my_test_api_client/async_api/users.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from ..client import AuthenticatedClient, Client
88
from ..errors import ApiResponseError
99
from ..models.a_model import AModel
10-
from ..models.an_enum_value import AnEnumValue
10+
from ..models.an_enum import AnEnum
1111
from ..models.body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost
1212
from ..models.http_validation_error import HTTPValidationError
1313

1414

1515
async def get_user_list(
16-
*, client: Client, an_enum_value: List[AnEnumValue], some_date: Union[date, datetime],
16+
*, client: Client, an_enum_value: List[AnEnum], some_date: Union[date, datetime],
1717
) -> Union[
1818
List[AModel], HTTPValidationError,
1919
]:
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
""" Contains all the data models used in inputs/outputs """
22

33
from .a_model import AModel
4-
from .an_enum_value import AnEnumValue
5-
from .an_enum_value1 import AnEnumValue1
4+
from .an_enum import AnEnum
65
from .body_upload_file_tests_upload_post import BodyUploadFileTestsUploadPost
6+
from .different_enum import DifferentEnum
77
from .http_validation_error import HTTPValidationError
88
from .types import *
99
from .validation_error import ValidationError

end_to_end_tests/golden-master/my_test_api_client/models/a_model.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
from datetime import date, datetime
55
from typing import Any, Dict, List, Optional, Union, cast
66

7-
from .an_enum_value import AnEnumValue
8-
from .an_enum_value1 import AnEnumValue1
7+
from .an_enum import AnEnum
8+
from .different_enum import DifferentEnum
99

1010

1111
@dataclass
1212
class AModel:
1313
""" A Model for testing all the ways custom objects can be used """
1414

15-
an_enum_value: AnEnumValue
15+
an_enum_value: AnEnum
1616
a_camel_date_time: Union[datetime, date]
1717
a_date: date
18-
nested_list_of_enums: Optional[List[List[AnEnumValue1]]] = field(
19-
default_factory=lambda: cast(Optional[List[List[AnEnumValue1]]], [])
18+
nested_list_of_enums: Optional[List[List[DifferentEnum]]] = field(
19+
default_factory=lambda: cast(Optional[List[List[DifferentEnum]]], [])
2020
)
2121
some_dict: Optional[Dict[Any, Any]] = field(default_factory=lambda: cast(Optional[Dict[Any, Any]], {}))
2222

@@ -56,7 +56,7 @@ def to_dict(self) -> Dict[str, Any]:
5656

5757
@staticmethod
5858
def from_dict(d: Dict[str, Any]) -> AModel:
59-
an_enum_value = AnEnumValue(d["an_enum_value"])
59+
an_enum_value = AnEnum(d["an_enum_value"])
6060

6161
def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime, date]:
6262
a_camel_date_time: Union[datetime, date]
@@ -78,7 +78,7 @@ def _parse_a_camel_date_time(data: Dict[str, Any]) -> Union[datetime, date]:
7878
for nested_list_of_enums_item_data in d.get("nested_list_of_enums") or []:
7979
nested_list_of_enums_item = []
8080
for nested_list_of_enums_item_item_data in nested_list_of_enums_item_data:
81-
nested_list_of_enums_item_item = AnEnumValue1(nested_list_of_enums_item_item_data)
81+
nested_list_of_enums_item_item = DifferentEnum(nested_list_of_enums_item_item_data)
8282

8383
nested_list_of_enums_item.append(nested_list_of_enums_item_item)
8484

Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from enum import Enum
22

33

4-
class AnEnumValue(str, Enum):
4+
class AnEnum(str, Enum):
55
FIRST_VALUE = "FIRST_VALUE"
66
SECOND_VALUE = "SECOND_VALUE"
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from enum import Enum
22

33

4-
class AnEnumValue1(str, Enum):
4+
class DifferentEnum(str, Enum):
55
DIFFERENT = "DIFFERENT"
66
OTHER = "OTHER"

openapi_python_client/parser/openapi.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,14 @@ class Model:
208208
relative_imports: Set[str]
209209

210210
@staticmethod
211-
def from_data(*, data: Union[oai.Reference, oai.Schema], name: str) -> Union[Model, ParseError]:
211+
def from_data(*, data: oai.Schema, name: str) -> Union[Model, ParseError]:
212212
""" A single Model from its OAI data
213213
214214
Args:
215215
data: Data of a single Schema
216216
name: Name by which the schema is referenced, such as a model name.
217217
Used to infer the type name if a `title` property is not available.
218218
"""
219-
if isinstance(data, oai.Reference):
220-
return ParseError(data=data, detail="Reference schemas are not supported.")
221219
required_set = set(data.required or [])
222220
required_properties: List[Property] = []
223221
optional_properties: List[Property] = []
@@ -258,6 +256,18 @@ def build(*, schemas: Dict[str, Union[oai.Reference, oai.Schema]]) -> Schemas:
258256
""" Get a list of Schemas from an OpenAPI dict """
259257
result = Schemas()
260258
for name, data in schemas.items():
259+
if isinstance(data, oai.Reference):
260+
result.errors.append(ParseError(data=data, detail="Reference schemas are not supported."))
261+
continue
262+
if data.enum is not None:
263+
EnumProperty(
264+
name=name,
265+
title=data.title or name,
266+
required=True,
267+
default=data.default,
268+
values=EnumProperty.values_from_list(data.enum),
269+
)
270+
continue
261271
s = Model.from_data(data=data, name=name)
262272
if isinstance(s, ParseError):
263273
result.errors.append(s)

openapi_python_client/parser/properties.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,11 @@ def get_all_enums() -> Dict[str, EnumProperty]:
263263
""" Get all the EnumProperties that have been registered keyed by class name """
264264
return _existing_enums
265265

266+
@staticmethod
267+
def get_enum(name: str) -> Optional[EnumProperty]:
268+
""" Get all the EnumProperties that have been registered keyed by class name """
269+
return _existing_enums.get(name)
270+
266271
def get_type_string(self) -> str:
267272
""" Get a string representation of type that should be used when declaring this property """
268273

@@ -304,7 +309,12 @@ class RefProperty(Property):
304309

305310
reference: Reference
306311

307-
template: ClassVar[str] = "ref_property.pyi"
312+
@property
313+
def template(self) -> str: # type: ignore
314+
enum = EnumProperty.get_enum(self.reference.class_name)
315+
if enum:
316+
return "enum_property.pyi"
317+
return "ref_property.pyi"
308318

309319
def get_type_string(self) -> str:
310320
""" Get a string representation of type that should be used when declaring this property """

0 commit comments

Comments
 (0)