Skip to content

Fix DataType deepcopy infinite recursion with circular references#2852

Merged
koxudaxi merged 2 commits intomainfrom
fix/datatype-deepcopy-recursion
Dec 29, 2025
Merged

Fix DataType deepcopy infinite recursion with circular references#2852
koxudaxi merged 2 commits intomainfrom
fix/datatype-deepcopy-recursion

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 29, 2025

Summary by CodeRabbit

  • New Features

    • Added deep copy capability for data types and configuration objects, enabling creation of independent copies with automatic circular reference handling.
  • Tests

    • Expanded test coverage for deep copy functionality, including circular references, nested structures, memoization, and edge cases.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 29, 2025

📝 Walkthrough

Walkthrough

Adds __deepcopy__ methods to DataType and Config classes to enable safe deep copying with circular reference handling. Includes comprehensive test coverage for various deepcopy scenarios including nested structures, memoization behavior, and circular parent-child relationships.

Changes

Cohort / File(s) Summary
DataType and Config deepcopy implementation
src/datamodel_code_generator/types.py
Added __deepcopy__ methods to DataType and Config classes with memo-based circular reference tracking, shallow field-wise construction, and recursive deepcopy of non-excluded fields (parent/children excluded).
Deepcopy test coverage
tests/test_types.py
Added 5 test functions covering circular reference handling, nested DataType preservation, memoization cache behavior, and None memo edge cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Deep copies crafted with care and grace,
Circular references know their place!
Memo tracks all through the rabbit's warren,
DataTypes cloned without a worry or sorrow'n! 🥕

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 clearly and specifically describes the main change: adding deepcopy support with circular reference handling to DataType.
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/datatype-deepcopy-recursion

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

github-actions Bot commented Dec 29, 2025

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

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 29, 2025

CodSpeed Performance Report

Merging #2852 will not alter performance

Comparing fix/datatype-deepcopy-recursion (d039eb7) with main (055f8ed)

⚠️ 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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 29, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.50%. Comparing base (16f27ef) to head (d039eb7).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##             main    #2852    +/-   ##
========================================
  Coverage   99.50%   99.50%            
========================================
  Files          90       90            
  Lines       14489    14689   +200     
  Branches     1736     1754    +18     
========================================
+ Hits        14417    14617   +200     
  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.

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)
tests/test_types.py (1)

243-274: Good coverage for edge cases.

Both tests appropriately cover:

  • memo=None initialization (line 252)
  • Memo cache hit returning the same object (lines 269-274)

The # noqa comments are flagged by static analysis as unnecessary for the current Ruff configuration. You may optionally remove them for cleaner code, though keeping them is harmless if you want to guard against other linters.

Optional: Remove unused noqa directives
-    from datamodel_code_generator.model.base import DataModelFieldBase  # noqa: F401
+    from datamodel_code_generator.model.base import DataModelFieldBase

Apply similar changes to lines 166, 190, 217, 246, 262, and remove # noqa: PLC2801 from lines 252, 269, 274.

📜 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 16f27ef and d039eb7.

📒 Files selected for processing (2)
  • src/datamodel_code_generator/types.py
  • tests/test_types.py
🧰 Additional context used
🧬 Code graph analysis (2)
src/datamodel_code_generator/types.py (1)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
tests/test_types.py (1)
src/datamodel_code_generator/types.py (1)
  • DataType (297-838)
🪛 Ruff (0.14.10)
tests/test_types.py

166-166: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


190-190: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


217-217: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


246-246: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


252-252: Unused noqa directive (non-enabled: PLC2801)

Remove unused noqa directive

(RUF100)


262-262: Unused noqa directive (non-enabled: F401)

Remove unused noqa directive

(RUF100)


269-269: Unused noqa directive (non-enabled: PLC2801)

Remove unused noqa directive

(RUF100)


274-274: Unused noqa directive (non-enabled: PLC2801)

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). (12)
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: 3.14 on Ubuntu
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (4)
tests/test_types.py (3)

157-182: Good test coverage for circular reference handling.

This test correctly validates that:

  1. Deepcopy doesn't cause infinite recursion
  2. Excluded fields (parent, children) are set to None in the copy
  3. Non-excluded fields (type) are properly copied

185-209: Solid test for deep copy independence.

The test correctly validates that:

  1. Nested data_types structure is preserved
  2. Modifying the original doesn't affect the copy (line 208-209)

212-240: Excellent memoization behavior test.

The assertion on line 240 correctly validates that memoization returns the same copied object when the original shared DataType is encountered multiple times during deepcopy traversal.

src/datamodel_code_generator/types.py (1)

358-388: Well-implemented deepcopy with proper cycle handling.

The two-phase approach (shallow construct first, then deep copy fields) correctly prevents infinite recursion by registering the new object in memo before recursing into nested fields. Setting children and parent to None is intentional and explicitly tested behavior—it breaks circular references in the parent-children graph relationship. This is documented in the existing docstring and validated by the test suite, which confirms children is None after deepcopy.

@koxudaxi koxudaxi merged commit 36d102c into main Dec 29, 2025
37 checks passed
@koxudaxi koxudaxi deleted the fix/datatype-deepcopy-recursion branch December 29, 2025 09:41
@github-actions
Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR adds a __deepcopy__ method to the DataType class to fix infinite recursion that occurred when deepcopying DataType objects with circular references through parent/children fields. This is purely a bug fix that: (1) fixes previously broken behavior (RecursionError), (2) does not change any public API or CLI options, (3) does not affect generated code output, (4) does not require template updates, and (5) does not change any default configuration. The fix intentionally excludes parent and children fields from the deep copy (setting them to None), which is the correct behavior to prevent circular reference issues. Any code that worked before will continue to work, and code that was broken (deepcopy with circular refs) now works correctly.


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