diff --git a/README.md b/README.md index 4baa93c9e..6e1a93906 100644 --- a/README.md +++ b/README.md @@ -127,8 +127,7 @@ package_name_override: my_extra_special_package_name ### field_prefix -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\_". +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. Example: diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py index 889237c7b..9c1740dc8 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/a_model.py @@ -35,6 +35,7 @@ class AModel: a_nullable_date (Optional[datetime.date]): a_not_required_date (Union[Unset, datetime.date]): attr_1_leading_digit (Union[Unset, str]): + attr_leading_underscore (Union[Unset, str]): required_nullable (Optional[str]): not_required_nullable (Union[Unset, None, str]): not_required_not_nullable (Union[Unset, str]): @@ -62,6 +63,7 @@ class AModel: nested_list_of_enums: Union[Unset, List[List[DifferentEnum]]] = UNSET a_not_required_date: Union[Unset, datetime.date] = UNSET attr_1_leading_digit: Union[Unset, str] = UNSET + attr_leading_underscore: Union[Unset, str] = UNSET not_required_nullable: Union[Unset, None, str] = UNSET not_required_not_nullable: Union[Unset, str] = UNSET not_required_one_of_models: Union["FreeFormModel", "ModelWithUnionProperty", Unset] = UNSET @@ -123,6 +125,7 @@ def to_dict(self) -> Dict[str, Any]: a_not_required_date = self.a_not_required_date.isoformat() attr_1_leading_digit = self.attr_1_leading_digit + attr_leading_underscore = self.attr_leading_underscore required_nullable = self.required_nullable not_required_nullable = self.not_required_nullable not_required_not_nullable = self.not_required_not_nullable @@ -207,6 +210,8 @@ def to_dict(self) -> Dict[str, Any]: field_dict["a_not_required_date"] = a_not_required_date if attr_1_leading_digit is not UNSET: field_dict["1_leading_digit"] = attr_1_leading_digit + if attr_leading_underscore is not UNSET: + field_dict["_leading_underscore"] = attr_leading_underscore if not_required_nullable is not UNSET: field_dict["not_required_nullable"] = not_required_nullable if not_required_not_nullable is not UNSET: @@ -313,6 +318,8 @@ def _parse_one_of_models(data: object) -> Union["FreeFormModel", "ModelWithUnion attr_1_leading_digit = d.pop("1_leading_digit", UNSET) + attr_leading_underscore = d.pop("_leading_underscore", UNSET) + required_nullable = d.pop("required_nullable") not_required_nullable = d.pop("not_required_nullable", UNSET) @@ -447,6 +454,7 @@ def _parse_not_required_nullable_one_of_models( a_nullable_date=a_nullable_date, a_not_required_date=a_not_required_date, attr_1_leading_digit=attr_1_leading_digit, + attr_leading_underscore=attr_leading_underscore, required_nullable=required_nullable, not_required_nullable=not_required_nullable, not_required_not_nullable=not_required_not_nullable, diff --git a/end_to_end_tests/openapi.json b/end_to_end_tests/openapi.json index 158b30845..803bedfeb 100644 --- a/end_to_end_tests/openapi.json +++ b/end_to_end_tests/openapi.json @@ -1327,6 +1327,10 @@ "title": "Leading Digit", "type": "string" }, + "_leading_underscore": { + "title": "Leading Underscore", + "type": "string" + }, "required_nullable": { "title": "Required AND Nullable", "type": "string", diff --git a/openapi_python_client/__init__.py b/openapi_python_client/__init__.py index ff0a132ca..32c0046d6 100644 --- a/openapi_python_client/__init__.py +++ b/openapi_python_client/__init__.py @@ -155,9 +155,8 @@ def _run_command(self, cmd: str) -> None: ) return try: - subprocess.run( - cmd, cwd=self.project_dir, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True - ) + cwd = self.package_dir if self.meta == MetaType.NONE else self.project_dir + subprocess.run(cmd, cwd=cwd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True) except CalledProcessError as err: self.errors.append( GeneratorError( diff --git a/openapi_python_client/utils.py b/openapi_python_client/utils.py index cb1ac611c..c16237533 100644 --- a/openapi_python_client/utils.py +++ b/openapi_python_client/utils.py @@ -12,7 +12,7 @@ class PythonIdentifier(str): def __new__(cls, value: str, prefix: str) -> "PythonIdentifier": new_value = fix_reserved_words(snake_case(sanitize(value))) - if not new_value.isidentifier(): + if not new_value.isidentifier() or value.startswith("_"): new_value = f"{prefix}{new_value}" return str.__new__(cls, new_value)