From 65735cb4b76d646c73a1229ca943bb31dd47b9c6 Mon Sep 17 00:00:00 2001 From: Eric Yen Date: Wed, 12 Nov 2025 12:42:36 -0800 Subject: [PATCH 1/4] update uuid property template --- .../templates/property_templates/uuid_property.py.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi_python_client/templates/property_templates/uuid_property.py.jinja b/openapi_python_client/templates/property_templates/uuid_property.py.jinja index 3a6ce46bb..ec51a5ef5 100644 --- a/openapi_python_client/templates/property_templates/uuid_property.py.jinja +++ b/openapi_python_client/templates/property_templates/uuid_property.py.jinja @@ -27,5 +27,5 @@ if not isinstance({{ source }}, Unset): {% endmacro %} {% macro multipart(property, source, name) %} -files.append(({{ name }}, (None, str({{ source }}), "text/plain")) +files.append(({{ name }}, (None, str({{ source }}), "text/plain"))) {% endmacro %} From 9c27e4fb9ebd1fe851d8042a31bd5856c6f6c0bc Mon Sep 17 00:00:00 2001 From: Eric Yen Date: Wed, 12 Nov 2025 13:01:55 -0800 Subject: [PATCH 2/4] add test for uuid property template --- .../test_uuid_property/__init__.py | 1 + .../test_uuid_property/test_uuid_multipart.py | 70 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tests/test_templates/test_property_templates/test_uuid_property/__init__.py create mode 100644 tests/test_templates/test_property_templates/test_uuid_property/test_uuid_multipart.py diff --git a/tests/test_templates/test_property_templates/test_uuid_property/__init__.py b/tests/test_templates/test_property_templates/test_uuid_property/__init__.py new file mode 100644 index 000000000..839bd41fd --- /dev/null +++ b/tests/test_templates/test_property_templates/test_uuid_property/__init__.py @@ -0,0 +1 @@ +"""Tests for UUID property templates.""" diff --git a/tests/test_templates/test_property_templates/test_uuid_property/test_uuid_multipart.py b/tests/test_templates/test_property_templates/test_uuid_property/test_uuid_multipart.py new file mode 100644 index 000000000..fe7cd7f85 --- /dev/null +++ b/tests/test_templates/test_property_templates/test_uuid_property/test_uuid_multipart.py @@ -0,0 +1,70 @@ +"""Tests for UUID property multipart macro functionality.""" + +from pathlib import Path +from typing import Any +from uuid import UUID + +import jinja2 +import pytest + +from openapi_python_client.parser.properties import UuidProperty +from openapi_python_client.utils import PythonIdentifier + + +def uuid_property(required: bool = True, default: Any = None) -> UuidProperty: + """Helper to create a UuidProperty for testing.""" + return UuidProperty( + name="test_uuid", + required=required, + default=default, + python_name=PythonIdentifier(value="test_uuid", prefix=""), + description="A test UUID property", + example="550e8400-e29b-41d4-a716-446655440000", + ) + + +@pytest.fixture +def jinja_env() -> jinja2.Environment: + """Create a Jinja2 environment with the property templates loaded.""" + templates_dir = Path(__file__).parent.parent.parent.parent.parent / "openapi_python_client" / "templates" + env = jinja2.Environment( + loader=jinja2.FileSystemLoader(templates_dir), + trim_blocks=True, + lstrip_blocks=True, + ) + return env + + +def test_multipart_macro_generates_syntactically_correct_code_for_required_uuid(jinja_env: jinja2.Environment) -> None: + """Test that the multipart macro generates syntactically correct Python code for required UUID properties.""" + prop = uuid_property(required=True) + + template = jinja_env.get_template("property_templates/uuid_property.py.jinja") + + # Render the multipart macro + multipart_code = template.module.multipart(prop, "test_uuid", '"test_uuid"') # type: ignore[attr-defined] + + # Verify the generated code is syntactically correct + expected = 'files.append(("test_uuid", (None, str(test_uuid), "text/plain")))' + assert multipart_code.strip() == expected + + # Verify it compiles as valid Python + compile(multipart_code, "", "exec") + + +def test_multipart_macro_generates_syntactically_correct_code_for_optional_uuid(jinja_env: jinja2.Environment) -> None: + """Test that the multipart macro generates syntactically correct Python code for optional UUID properties.""" + prop = uuid_property(required=False) + + template = jinja_env.get_template("property_templates/uuid_property.py.jinja") + + # Render the multipart macro + multipart_code = template.module.multipart(prop, "test_uuid", '"test_uuid"') # type: ignore[attr-defined] + + # Verify the generated code is syntactically correct + expected = 'files.append(("test_uuid", (None, str(test_uuid), "text/plain")))' + assert multipart_code.strip() == expected + + # Verify it compiles as valid Python + compile(multipart_code, "", "exec") + \ No newline at end of file From e1c5d996cf43b027bfbf1d80fdb0ab7ffaa9d5d4 Mon Sep 17 00:00:00 2001 From: Eric Yen Date: Wed, 12 Nov 2025 13:48:23 -0800 Subject: [PATCH 3/4] add missing lazy import for to_multipart generation --- .../models/body_upload_file_tests_upload_post.py | 4 ++++ openapi_python_client/templates/model.py.jinja | 3 +++ 2 files changed, 7 insertions(+) diff --git a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py index 959cdccc8..628ed2ccd 100644 --- a/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py +++ b/end_to_end_tests/golden-record/my_test_api_client/models/body_upload_file_tests_upload_post.py @@ -172,6 +172,10 @@ def to_dict(self) -> dict[str, Any]: return field_dict def to_multipart(self) -> types.RequestFiles: + from ..models.body_upload_file_tests_upload_post_some_nullable_object import ( + BodyUploadFileTestsUploadPostSomeNullableObject, + ) + files: types.RequestFiles = [] files.append(("some_file", self.some_file.to_tuple())) diff --git a/openapi_python_client/templates/model.py.jinja b/openapi_python_client/templates/model.py.jinja index 785b49e68..48da03422 100644 --- a/openapi_python_client/templates/model.py.jinja +++ b/openapi_python_client/templates/model.py.jinja @@ -151,6 +151,9 @@ return field_dict {% if model.is_multipart_body %} def to_multipart(self) -> types.RequestFiles: + {% for lazy_import in model.lazy_imports %} + {{ lazy_import }} + {% endfor %} files: types.RequestFiles = [] {% for property in model.required_properties + model.optional_properties %} From ee34b6034ef6da1c630e0bcf6a7920890ac3cb5e Mon Sep 17 00:00:00 2001 From: Eric Yen Date: Wed, 12 Nov 2025 14:00:33 -0800 Subject: [PATCH 4/4] add changeset file for knope --- .changeset/fix_bad_code_generation.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/fix_bad_code_generation.md diff --git a/.changeset/fix_bad_code_generation.md b/.changeset/fix_bad_code_generation.md new file mode 100644 index 000000000..2f5b99158 --- /dev/null +++ b/.changeset/fix_bad_code_generation.md @@ -0,0 +1,13 @@ +--- +default: patch +--- + +# Fix bad code generation + +#1360 by @EricAtORS + +This fixes: +- missing parenthesis in to_multipart + #1338 #1318 +- missing imports in the lazy eval in to_multipart: +#931 and #1051