Skip to content

Commit 5560f54

Browse files
committed
Allow case sensitive enum values
1 parent ae47096 commit 5560f54

File tree

5 files changed

+55
-16
lines changed

5 files changed

+55
-16
lines changed

openapi_python_client/config.py

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class ConfigFile(BaseModel):
4343
post_hooks: Optional[List[str]] = None
4444
field_prefix: str = "field_"
4545
http_timeout: int = 5
46+
case_sensitive_enums: bool = False
4647

4748
@staticmethod
4849
def load_from_path(path: Path) -> "ConfigFile":
@@ -75,6 +76,7 @@ class Config:
7576
content_type_overrides: Dict[str, str]
7677
overwrite: bool
7778
output_path: Optional[Path]
79+
case_sensitive_enums: bool
7880

7981
@staticmethod
8082
def from_sources(
@@ -113,5 +115,6 @@ def from_sources(
113115
file_encoding=file_encoding,
114116
overwrite=overwrite,
115117
output_path=output_path,
118+
case_sensitive_enums=config_file.case_sensitive_enums,
116119
)
117120
return config

openapi_python_client/parser/properties/enum_property.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__all__ = ["EnumProperty"]
44

5-
from typing import Any, ClassVar, List, Union, cast
5+
from typing import Any, ClassVar, List, Sequence, Union, cast
66

77
from attr import evolve
88
from attrs import define
@@ -121,7 +121,7 @@ def build( # noqa: PLR0911
121121
if parent_name:
122122
class_name = f"{utils.pascal_case(parent_name)}{utils.pascal_case(class_name)}"
123123
class_info = Class.from_string(string=class_name, config=config)
124-
values = EnumProperty.values_from_list(value_list)
124+
values = EnumProperty.values_from_list(value_list, case_sensitive_enums=config.case_sensitive_enums)
125125

126126
if class_info.name in schemas.classes_by_name:
127127
existing = schemas.classes_by_name[class_info.name]
@@ -183,24 +183,30 @@ def get_imports(self, *, prefix: str) -> set[str]:
183183
return imports
184184

185185
@staticmethod
186-
def values_from_list(values: list[str] | list[int]) -> dict[str, ValueType]:
186+
def values_from_list(
187+
values: Sequence[str] | Sequence[int], case_sensitive_enums: bool = False
188+
) -> dict[str, ValueType]:
187189
"""Convert a list of values into dict of {name: value}, where value can sometimes be None"""
188190
output: dict[str, ValueType] = {}
189191

190-
for i, value in enumerate(values):
191-
value = cast(Union[str, int], value)
192+
for value in values:
192193
if isinstance(value, int):
193194
if value < 0:
194195
output[f"VALUE_NEGATIVE_{-value}"] = value
195196
else:
196197
output[f"VALUE_{value}"] = value
197198
continue
198-
if value and value[0].isalpha():
199-
key = value.upper()
199+
200+
if case_sensitive_enums:
201+
sanitized_key = utils.case_insensitive_snake_case(value)
200202
else:
201-
key = f"VALUE_{i}"
202-
if key in output:
203-
raise ValueError(f"Duplicate key {key} in Enum")
204-
sanitized_key = utils.snake_case(key).upper()
203+
sanitized_key = utils.snake_case(value.lower()).upper()
204+
if not value or not value[0].isalpha():
205+
sanitized_key = f"LITERAL_{sanitized_key}"
206+
207+
if sanitized_key in output:
208+
raise ValueError(f"Duplicate key {sanitized_key} in Enum")
209+
205210
output[sanitized_key] = utils.remove_string_escapes(value)
211+
206212
return output

openapi_python_client/utils.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,19 @@ def fix_reserved_words(value: str) -> str:
7777
return value
7878

7979

80+
def case_insensitive_snake_case(value: str) -> str:
81+
"""Converts to snake_case, but preserves capitalization of acronyms"""
82+
words = split_words(sanitize(value))
83+
value = "_".join(words)
84+
85+
return value
86+
87+
8088
def snake_case(value: str) -> str:
8189
"""Converts to snake_case"""
82-
words = split_words(sanitize(value))
83-
return "_".join(words).lower()
90+
value = case_insensitive_snake_case(value).lower()
91+
92+
return value
8493

8594

8695
def pascal_case(value: str) -> str:

tests/test_config.py

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def test_load_from_path(tmp_path: Path, filename, dump, relative):
3939
"project_name_override": "project-name",
4040
"package_name_override": "package_name",
4141
"package_version_override": "package_version",
42+
"case_sensitive_enums": True,
4243
}
4344
yml_file.write_text(dump(data))
4445

@@ -49,3 +50,4 @@ def test_load_from_path(tmp_path: Path, filename, dump, relative):
4950
assert config.project_name_override == "project-name"
5051
assert config.package_name_override == "package_name"
5152
assert config.package_version_override == "package_version"
53+
assert config.case_sensitive_enums is True

tests/test_parser/test_properties/test_init.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -355,13 +355,32 @@ def test_values_from_list(self):
355355

356356
assert result == {
357357
"ABC": "abc",
358-
"VALUE_1": "123",
358+
"LITERAL_123": "123",
359359
"A23": "a23",
360-
"VALUE_3": "1bc",
360+
"LITERAL_1BC": "1bc",
361361
"VALUE_4": 4,
362362
"VALUE_NEGATIVE_3": -3,
363363
"A_THING_WITH_SPACES": "a Thing WIth spaces",
364-
"VALUE_7": "",
364+
"LITERAL_": "",
365+
}
366+
367+
def test_values_from_list_with_case_sesitive(self):
368+
from openapi_python_client.parser.properties import EnumProperty
369+
370+
data = ["abc", "Abc", "123", "a23", "1bc", 4, -3, "a Thing WIth spaces", ""]
371+
372+
result = EnumProperty.values_from_list(data, case_sensitive_enums=True)
373+
374+
assert result == {
375+
"abc": "abc",
376+
"Abc": "Abc",
377+
"LITERAL_123": "123",
378+
"a23": "a23",
379+
"LITERAL_1bc": "1bc",
380+
"VALUE_4": 4,
381+
"VALUE_NEGATIVE_3": -3,
382+
"a_Thing_W_Ith_spaces": "a Thing WIth spaces",
383+
"LITERAL_": "",
365384
}
366385

367386
def test_values_from_list_duplicate(self):

0 commit comments

Comments
 (0)