Skip to content

Handle types.UnionType in _serialize_python_type for Python 3.10-3.13#2848

Merged
koxudaxi merged 1 commit intomainfrom
fix/serialize-python-type-union-type
Dec 28, 2025
Merged

Handle types.UnionType in _serialize_python_type for Python 3.10-3.13#2848
koxudaxi merged 1 commit intomainfrom
fix/serialize-python-type-union-type

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 28, 2025

Summary by CodeRabbit

  • New Features

    • Improved serialization to properly support Python 3.10–3.13 native union type syntax (X | Y) for better type representation.
    • Enhanced optional mapping type handling by supporting modern union syntax while maintaining backward compatibility with older Python versions.
  • Tests

    • Added test coverage to validate proper preservation and handling of union syntax in optional mapping type scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 28, 2025

📝 Walkthrough

Walkthrough

Adds support for PEP 604 union syntax (X | Y) in Python 3.10–3.13 by handling types.UnionType in the _serialize_python_type function. When the origin type matches UnionType, the code recursively serializes each argument and returns a pipe-delimited string if any nested types require preservation. Includes test model and test case to verify the new syntax handling.

Changes

Cohort / File(s) Summary
Union type serialization
src/datamodel_code_generator/__main__.py
Adds specialized path in _serialize_python_type to detect and handle types.UnionType for Python 3.10–3.13, recursively serializing union arguments and joining with " | " separator; guarded to exclude Python 3.14+ where UnionType overlaps with typing.Union
Test infrastructure
tests/data/python/input_model/pydantic_models.py, tests/test_input_model.py
Adds optional_mapping: Mapping[str, str] | None field to ModelWithPythonTypes model and corresponding test function test_input_model_optional_mapping_union_syntax to validate PEP 604 syntax preservation

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #2837: Implements the underlying preservation/serialization logic in _serialize_python_type that this PR builds upon for PEP 604 union type support.

Poem

🐰 Hop! The union types now dance in style,
With pipes instead of typing's guile,
Python 3.10 through thirteen shine,
Our code generator reads X | Y so fine!
Test cases bound, the syntax is right. ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding specialized handling for types.UnionType in _serialize_python_type for Python 3.10-3.13, which matches the primary code modification shown in the raw summary.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/serialize-python-type-union-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

📚 Docs Preview: https://pr-2848.datamodel-code-generator.pages.dev

@koxudaxi koxudaxi enabled auto-merge (squash) December 28, 2025 20:18
@koxudaxi koxudaxi merged commit 2aebb77 into main Dec 28, 2025
32 of 33 checks passed
@koxudaxi koxudaxi deleted the fix/serialize-python-type-union-type branch December 28, 2025 20:19
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 28, 2025

CodSpeed Performance Report

Merging #2848 will not alter performance

Comparing fix/serialize-python-type-union-type (885bfef) with main (a2a4d74)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

✅ 11 untouched
⏩ 98 skipped1

Footnotes

  1. 98 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/datamodel_code_generator/__main__.py (1)

635-656: LGTM! Well-implemented support for PEP 604 union syntax.

The implementation correctly handles types.UnionType (X | Y syntax) for Python 3.10-3.13:

  • Properly version-gates the logic by checking types.UnionType is not Union
  • Recursively serializes union arguments and preserves the | syntax when needed
  • Correctly falls back to _simple_type_name for standard types
  • The strict=False parameter in zip() is safe since this block only executes in Python 3.10+
Minor cleanup: Remove unused noqa directives

Static analysis indicates the # noqa: PLC0415 directives on lines 635, 636, and 645 may be unused (PLC0415 might not be enabled in your Ruff config). Consider removing them:

-    import types  # noqa: PLC0415
+    import types
-    from typing import get_args, get_origin  # noqa: PLC0415
+    from typing import get_args, get_origin

-    from typing import Union  # noqa: PLC0415
+    from typing import Union
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2a4d74 and 885bfef.

📒 Files selected for processing (3)
  • src/datamodel_code_generator/__main__.py
  • tests/data/python/input_model/pydantic_models.py
  • tests/test_input_model.py
🧰 Additional context used
🪛 Ruff (0.14.10)
src/datamodel_code_generator/__main__.py

635-635: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


636-636: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


645-645: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: build-deploy
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.11 on Ubuntu
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: Analyze (python)
🔇 Additional comments (2)
tests/data/python/input_model/pydantic_models.py (1)

36-36: LGTM! Test data correctly uses PEP 604 union syntax.

The addition of optional_mapping: Mapping[str, str] | None provides appropriate test coverage for the new types.UnionType handling in Python 3.10+.

tests/test_input_model.py (1)

595-606: LGTM! Comprehensive test for union syntax preservation.

The test correctly verifies that Mapping[str, str] | None (using PEP 604 syntax) is preserved in the generated output. The docstring provides helpful context about the Python version-specific behavior.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 28, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.50%. Comparing base (a2a4d74) to head (885bfef).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2848   +/-   ##
=======================================
  Coverage   99.50%   99.50%           
=======================================
  Files          90       90           
  Lines       14479    14489   +10     
  Branches     1735     1736    +1     
=======================================
+ Hits        14407    14417   +10     
  Misses         37       37           
  Partials       35       35           
Flag Coverage Δ
unittests 99.50% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR is a bug fix that adds proper handling for Python's native union type syntax (X | Y) using types.UnionType in Python 3.10-3.13. Before this fix, when using preserved types like Mapping in a union with the pipe syntax (e.g., Mapping[str, str] | None), the serialization would not work correctly. The change is purely additive - it adds handling for a case that was previously unhandled. No existing functionality is modified or removed, no CLI/API changes, no template changes, and no Python version support changes. Users who weren't using the pipe syntax with preserved types won't see any difference, and users who were will now get correct output.


This analysis was performed by Claude Code Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 1, 2026

🎉 Released in 0.51.0

This PR is now available in the latest release. See the release notes for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant