Skip to content

Commit de7ff75

Browse files
maxkomarychevdbanty
andcommitted
fix!: Treat leading underscore as a sign of invalid identifier [#703]. Thanks @maxkomarychev!
Co-authored-by: Dylan Anthony <[email protected]>
1 parent b4142b2 commit de7ff75

File tree

4 files changed

+14
-3
lines changed

4 files changed

+14
-3
lines changed

Diff for: README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ package_name_override: my_extra_special_package_name
127127

128128
### field_prefix
129129

130-
When generating properties, the `name` attribute of the OpenAPI schema will be used. When the `name` is not a valid
131-
Python identifier (e.g. begins with a number) this string will be prepended. Defaults to "field\_".
130+
When generating properties, the `name` attribute of the OpenAPI schema will be used. When the `name` is not a valid Python identifier (e.g. begins with a number) this string will be prepended. Defaults to "field\_". It will also be used to prefix fields in schema starting with "_" in order to avoid ambiguous semantics.
132131

133132
Example:
134133

Diff for: end_to_end_tests/golden-record/my_test_api_client/models/a_model.py

+8
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class AModel:
3535
a_nullable_date (Optional[datetime.date]):
3636
a_not_required_date (Union[Unset, datetime.date]):
3737
attr_1_leading_digit (Union[Unset, str]):
38+
attr_leading_underscore (Union[Unset, str]):
3839
required_nullable (Optional[str]):
3940
not_required_nullable (Union[Unset, None, str]):
4041
not_required_not_nullable (Union[Unset, str]):
@@ -62,6 +63,7 @@ class AModel:
6263
nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET
6364
a_not_required_date: Union[Unset, datetime.date] = UNSET
6465
attr_1_leading_digit: Union[Unset, str] = UNSET
66+
attr_leading_underscore: Union[Unset, str] = UNSET
6567
not_required_nullable: Union[Unset, None, str] = UNSET
6668
not_required_not_nullable: Union[Unset, str] = UNSET
6769
not_required_one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", Unset] = UNSET
@@ -123,6 +125,7 @@ def to_dict(self) -> Dict[str, Any]:
123125
a_not_required_date = self.a_not_required_date.isoformat()
124126

125127
attr_1_leading_digit = self.attr_1_leading_digit
128+
attr_leading_underscore = self.attr_leading_underscore
126129
required_nullable = self.required_nullable
127130
not_required_nullable = self.not_required_nullable
128131
not_required_not_nullable = self.not_required_not_nullable
@@ -207,6 +210,8 @@ def to_dict(self) -> Dict[str, Any]:
207210
field_dict["a_not_required_date"] = a_not_required_date
208211
if attr_1_leading_digit is not UNSET:
209212
field_dict["1_leading_digit"] = attr_1_leading_digit
213+
if attr_leading_underscore is not UNSET:
214+
field_dict["_leading_underscore"] = attr_leading_underscore
210215
if not_required_nullable is not UNSET:
211216
field_dict["not_required_nullable"] = not_required_nullable
212217
if not_required_not_nullable is not UNSET:
@@ -313,6 +318,8 @@ def _parse_one_of_models(data: object) -> Union["FreeFormModel", "ModelWithUnion
313318

314319
attr_1_leading_digit = d.pop("1_leading_digit", UNSET)
315320

321+
attr_leading_underscore = d.pop("_leading_underscore", UNSET)
322+
316323
required_nullable = d.pop("required_nullable")
317324

318325
not_required_nullable = d.pop("not_required_nullable", UNSET)
@@ -447,6 +454,7 @@ def _parse_not_required_nullable_one_of_models(
447454
a_nullable_date=a_nullable_date,
448455
a_not_required_date=a_not_required_date,
449456
attr_1_leading_digit=attr_1_leading_digit,
457+
attr_leading_underscore=attr_leading_underscore,
450458
required_nullable=required_nullable,
451459
not_required_nullable=not_required_nullable,
452460
not_required_not_nullable=not_required_not_nullable,

Diff for: end_to_end_tests/openapi.json

+4
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,10 @@
13271327
"title": "Leading Digit",
13281328
"type": "string"
13291329
},
1330+
"_leading_underscore": {
1331+
"title": "Leading Underscore",
1332+
"type": "string"
1333+
},
13301334
"required_nullable": {
13311335
"title": "Required AND Nullable",
13321336
"type": "string",

Diff for: openapi_python_client/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class PythonIdentifier(str):
1212
def __new__(cls, value: str, prefix: str) -> "PythonIdentifier":
1313
new_value = fix_reserved_words(snake_case(sanitize(value)))
1414

15-
if not new_value.isidentifier():
15+
if not new_value.isidentifier() or value.startswith("_"):
1616
new_value = f"{prefix}{new_value}"
1717
return str.__new__(cls, new_value)
1818

0 commit comments

Comments
 (0)