diff --git a/src/openapi_python_generator/language_converters/python/common.py b/src/openapi_python_generator/language_converters/python/common.py index e3c55c4..d4acb4b 100644 --- a/src/openapi_python_generator/language_converters/python/common.py +++ b/src/openapi_python_generator/language_converters/python/common.py @@ -55,3 +55,11 @@ def normalize_symbol(symbol: str) -> str: if normalized_symbol in keyword.kwlist: normalized_symbol = normalized_symbol + "_" return normalized_symbol + + +def safe_property_name(name: str) -> str: + return re.sub( + r"^(\d.*)", + r"var_\1", + name.replace("@", "").replace("-", "_"), + ) diff --git a/src/openapi_python_generator/language_converters/python/jinja_config.py b/src/openapi_python_generator/language_converters/python/jinja_config.py index 25505f7..15faf8c 100644 --- a/src/openapi_python_generator/language_converters/python/jinja_config.py +++ b/src/openapi_python_generator/language_converters/python/jinja_config.py @@ -19,7 +19,7 @@ def create_jinja_env(): custom_template_path = common.get_custom_template_path() - return Environment( + environment = Environment( loader=( ChoiceLoader( [ @@ -33,3 +33,5 @@ def create_jinja_env(): autoescape=True, trim_blocks=True, ) + environment.filters["safe_property_name"] = common.safe_property_name + return environment diff --git a/src/openapi_python_generator/language_converters/python/model_generator.py b/src/openapi_python_generator/language_converters/python/model_generator.py index 94bf647..23bb8d9 100644 --- a/src/openapi_python_generator/language_converters/python/model_generator.py +++ b/src/openapi_python_generator/language_converters/python/model_generator.py @@ -278,7 +278,7 @@ def generate_models(components: Components, pydantic_version: PydanticVersion = name = common.normalize_symbol(schema_name) if schema_or_reference.enum is not None: value_dict = schema_or_reference.dict() - regex = re.compile(r"[\s\/=\*\+]+") + regex = re.compile(r"[\s\/=\*\+\-]+") value_dict["enum"] = [ re.sub(regex, "_", i) if isinstance(i, str) else f"value_{i}" for i in value_dict["enum"] diff --git a/src/openapi_python_generator/language_converters/python/templates/models.jinja2 b/src/openapi_python_generator/language_converters/python/templates/models.jinja2 index e2a90aa..08abc34 100644 --- a/src/openapi_python_generator/language_converters/python/templates/models.jinja2 +++ b/src/openapi_python_generator/language_converters/python/templates/models.jinja2 @@ -18,5 +18,5 @@ class {{ schema_name }}(BaseModel): """ {% for property in properties %} - {{ property.name | replace("@","") | replace("-","_") }} : {{ property.type.converted_type | safe }} = Field(alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %}) + {{ property.name | safe_property_name }} : {{ property.type.converted_type | safe }} = Field(alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %}) {% endfor %} diff --git a/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 b/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 index 7d4cfbd..2c00bca 100644 --- a/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 +++ b/src/openapi_python_generator/language_converters/python/templates/models_pydantic_2.jinja2 @@ -22,5 +22,5 @@ class {{ schema_name }}(BaseModel): } {% for property in properties %} - {{ property.name | replace("@","") | replace("-","_") }} : {{ property.type.converted_type | safe }} = Field(validation_alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %}) - {% endfor %} \ No newline at end of file + {{ property.name | safe_property_name }} : {{ property.type.converted_type | safe }} = Field(validation_alias="{{ property.name }}" {% if not property.required %}, default = {{ property.default }} {% endif %}) + {% endfor %} diff --git a/tests/regression/test_issue_87.py b/tests/regression/test_issue_87.py new file mode 100644 index 0000000..6ed1544 --- /dev/null +++ b/tests/regression/test_issue_87.py @@ -0,0 +1,33 @@ +import pytest +from click.testing import CliRunner + +from openapi_python_generator.__main__ import main +from openapi_python_generator.common import HTTPLibrary +from tests.conftest import test_data_folder +from tests.conftest import test_result_path + + +@pytest.fixture +def runner() -> CliRunner: + """Fixture for invoking command-line interfaces.""" + return CliRunner() + + +@pytest.mark.parametrize( + "library", + [HTTPLibrary.httpx, HTTPLibrary.aiohttp, HTTPLibrary.requests], +) +def test_issue_87(runner: CliRunner, model_data_with_cleanup, library) -> None: + """ + https://github.com/MarcoMuellner/openapi-python-generator/issues/87 + """ + result = runner.invoke( + main, + [ + str(test_data_folder / "issue_87.json"), + str(test_result_path), + "--library", + library.value, + ], + ) + assert result.exit_code == 0 diff --git a/tests/test_data/issue_87.json b/tests/test_data/issue_87.json new file mode 100644 index 0000000..2db1bcc --- /dev/null +++ b/tests/test_data/issue_87.json @@ -0,0 +1,73 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Title", + "version": "1.0" + }, + "paths": { + "/users": { + "get": { + "summary": "Get users", + "description": "Returns a list of users.", + "operationId": "users_get", + "parameters": [ + { + "name": "type", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/UserType" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/User" + } + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "UserType": { + "title": "UserType", + "description": "An enumeration.", + "enum": [ + "admin-user", + "regular-user" + ] + }, + "User": { + "title": "User", + "description": "A user.", + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/UserType" + }, + "30d_active": { + "type": "boolean" + } + } + } + } + } +}