Skip to content

fix: quote forward references in recursive RootModel generic parameters#2720

Merged
koxudaxi merged 1 commit intomainfrom
fix/recursive-rootmodel-forward-refs
Dec 21, 2025
Merged

fix: quote forward references in recursive RootModel generic parameters#2720
koxudaxi merged 1 commit intomainfrom
fix/recursive-rootmodel-forward-refs

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 21, 2025

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved handling of recursive type aliases with Pydantic v2 RootModel types, ensuring proper forward reference resolution.
  • Tests

    • Added test coverage for Pydantic v2 recursive type alias generation scenarios.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 21, 2025

Walkthrough

Updates the parser to include RootModel in forward reference handling during type alias updates. Adds comprehensive test coverage for recursive type aliases with Pydantic v2, including expected output file and corresponding test function to validate the functionality.

Changes

Cohort / File(s) Summary
Core Parser Enhancement
src/datamodel_code_generator/parser/base.py
Modified __update_type_aliases method to treat pydantic_model_v2.RootModel the same as TypeAliasBase when determining models to process. Updated docstring to reflect RootModel handling.
Test Data & Expected Output
tests/data/expected/main/openapi/type_alias_recursive_pydantic_v2.py
New test data file introducing Pydantic v2 models with recursive type aliases: File (BaseModel), Folder (BaseModel with recursive subfolders), ElementaryType (RootModel for primitives), JsonType (RootModel for recursive JSON structure), Space and DualSpace (BaseModels with mutual references). Includes model rebuild calls for schema refresh.
Test Cases
tests/main/openapi/test_main_openapi.py
Added test_main_openapi_type_alias_recursive_pydantic_v2() function to validate recursive type alias handling with Pydantic v2 models, mirroring existing Pydantic v1 test but targeting pydantic_v2.BaseModel output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Parser logic change: Small condition update in __update_type_aliases, straightforward addition of RootModel handling
  • Test data file: Larger expected output file with multiple interrelated model definitions and recursive references—verify structure matches intended Pydantic v2 schema
  • Test function: Standard test pattern, but verify it properly exercises the recursive type alias behavior with RootModel

Poem

🐰 Roots grow deep in forward's refs,
Models linking, no regrets,
RootModel joins the alias dance,
Recursive types get their chance,
Tests confirm the schema's 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 fix: updating RootModel handling to properly quote forward references in recursive generic parameters, which aligns with the changes made to __update_type_aliases and the new test for Pydantic v2.
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/recursive-rootmodel-forward-refs

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.

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/parser/base.py (1)

392-415: Field-based dependency ordering for RootModel is reasonable, minor duplication only

Using field data_type references instead of base_classes for pydantic_model_v2.RootModel when computing indexes ensures recursive RootModels are ordered after their dependencies instead of being treated as independent. The comprehension is clear and matches the existing base-class logic.

If more model types gain special dependency rules later, consider extracting this into a small helper like _unresolved_dep_indexes(model, unresolved_paths) to avoid repeating the index-computation pattern, but it's not necessary for this change.

📜 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 3aeab90 and 60f7995.

📒 Files selected for processing (3)
  • src/datamodel_code_generator/parser/base.py (1 hunks)
  • tests/data/expected/main/openapi/type_alias_recursive_pydantic_v2.py (1 hunks)
  • tests/main/openapi/test_main_openapi.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/data/expected/main/openapi/type_alias_recursive_pydantic_v2.py (1)
src/datamodel_code_generator/model/base.py (1)
  • path (680-682)
src/datamodel_code_generator/parser/base.py (2)
src/datamodel_code_generator/model/type_alias.py (1)
  • TypeAliasBase (21-33)
src/datamodel_code_generator/model/pydantic_v2/root_model.py (1)
  • RootModel (13-35)
🔇 Additional comments (4)
src/datamodel_code_generator/parser/base.py (2)

129-134: RootModel inclusion in dependency pruning exception looks correct

Extending the use_deferred_annotations guard to keep field_refs for both TypeAliasBase and pydantic_model_v2.RootModel keeps their field-based dependencies visible to _reorder_models_keep_model_order, which is consistent with how forward-ref-sensitive models need to be ordered. No issues from a correctness perspective.


1895-1924: Extending __update_type_aliases to RootModel correctly covers recursive generics

Updating the docstring and isinstance check so that both TypeAliasBase and pydantic_model_v2.RootModel participate in forward-ref detection means:

  • References in RootModel fields to same-module models defined later get alias='"Name"' assigned.
  • model.has_forward_reference is now set for such RootModels, enabling the existing rebuild/forward-ref plumbing to work for them as well.

This aligns with the new recursive Pydantic v2 RootModel test and avoids NameError at class definition time for generic parameters. The logic is consistent with the existing type-alias handling.

tests/main/openapi/test_main_openapi.py (1)

3471-3488: New Pydantic v2 recursive RootModel test is well-aligned with existing coverage

The test wires type_alias_recursive.yaml to the new expected Pydantic v2 output, with arguments and naming consistent with the surrounding type-alias/recursive tests. It clearly documents the RootModel-specific forward-ref behavior and should reliably guard this regression.

tests/data/expected/main/openapi/type_alias_recursive_pydantic_v2.py (1)

1-46: Expected Pydantic v2 recursive RootModel output matches the intended behavior

The generated models correctly:

  • Use RootModel[...] for ElementaryType and JsonType.
  • Quote recursive JsonType references in the generic parameter (list["JsonType"], dict[str, "JsonType"]).
  • Include model_rebuild() calls for models that participate in forward references.

This aligns with the new test and the parser changes; the file looks syntactically and semantically sound as a golden output.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.34%. Comparing base (f4b074f) to head (60f7995).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2720   +/-   ##
=======================================
  Coverage   99.34%   99.34%           
=======================================
  Files          82       82           
  Lines       11615    11658   +43     
  Branches     1406     1410    +4     
=======================================
+ Hits        11539    11582   +43     
  Misses         45       45           
  Partials       31       31           
Flag Coverage Δ
unittests 99.34% <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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 21, 2025

CodSpeed Performance Report

Merging #2720 will not alter performance

Comparing fix/recursive-rootmodel-forward-refs (60f7995) with main (3aeab90)

Summary

✅ 59 untouched
⏩ 10 skipped1

Footnotes

  1. 10 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.

@koxudaxi koxudaxi merged commit e223a88 into main Dec 21, 2025
38 checks passed
@koxudaxi koxudaxi deleted the fix/recursive-rootmodel-forward-refs branch December 21, 2025 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant