Skip to content

Conversation

@koxudaxi
Copy link
Owner

@koxudaxi koxudaxi commented Jan 6, 2026

Fixes: #2940

Summary by CodeRabbit

  • New Features

    • Enhanced read-only and write-only field handling in OpenAPI schemas, particularly for schema references in request/response modes.
    • Improved resolution of nested type references to correctly point to variant models.
    • Automatic generation of base models for referenced schemas when needed.
  • Tests

    • Added test coverage for read-only/write-only reference request/response scenarios.

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 6, 2026

Warning

Rate limit exceeded

@koxudaxi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 6 minutes and 20 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between d825aec and d991965.

⛔ Files ignored due to path filters (1)
  • tests/data/openapi/read_only_write_only_ref_request_response.yaml is excluded by !tests/data/**/*.yaml and included by none
📒 Files selected for processing (8)
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • src/datamodel_code_generator/parser/schema_version.py
  • tests/data/expected/main/openapi/read_only_write_only_ref_request_response.py
  • tests/main/openapi/test_main_openapi.py
  • tests/parser/test_graphql.py
  • tests/parser/test_schema_version.py
📝 Walkthrough

Walkthrough

This PR fixes handling of $ref when using read-only-write-only-model-type option. It adds logic to detect when referenced schemas produce request/response variants and ensures field references point to the correct variant types. The OpenAPI parser is refactored to generate forced base models for referenced schemas lacking explicit models.

Changes

Cohort / File(s) Summary
Request/Response Variant Handling
src/datamodel_code_generator/parser/jsonschema.py
Introduces helper methods to determine if a referenced schema generates Request/Response variants. Adds recursive logic to update data type references in variant models and update field references to resolve to correct variant types before variant model creation.
OpenAPI Parser Refactoring
src/datamodel_code_generator/parser/openapi.py
Refactors parse_raw() by extracting core parsing logic into _parse_raw_impl(). Adds new _generate_forced_base_models() method to generate base models for referenced schemas lacking explicit models by temporarily forcing base model generation, with broad exception suppression for robustness.
Test Coverage
tests/main/openapi/test_main_openapi.py,
tests/data/expected/main/openapi/read_only_write_only_ref_request_response.py
Adds test case test_main_openapi_read_only_write_only_ref_request_response() to verify read-only/write-only handling with $ref in request/response mode. Includes expected output module defining Pydantic models for mixed, read-only, and write-only request/response structures.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

breaking-change-analyzed, breaking-change

Poem

🐰 A rabbit hops through refs with care,
To find where variants live and share,
With readOnly fields tucked away,
The variants now point the right way! ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing $ref handling in request-response mode for readOnly/writeOnly schemas, which matches the primary objective described in the linked issue.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #2940: it handles $ref to schemas with readOnly/writeOnly properties, ensures parent schemas generate variants when referencing schemas with readOnly/writeOnly fields, and uses correct variant references.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing $ref handling in request-response mode: jsonschema.py adds variant reference logic, openapi.py adds forced base model generation, and tests validate the fix.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.

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
Contributor

github-actions bot commented Jan 6, 2026

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

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 6, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing fix/read-only-write-only-ref-request-response (d991965) with main (c4d4b8d)

⚠️ 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 benchmarks
⏩ 98 skipped benchmarks1

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.

@koxudaxi koxudaxi force-pushed the fix/read-only-write-only-ref-request-response branch from 4755094 to d825aec Compare January 6, 2026 16:47
Copy link

@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 (2)
src/datamodel_code_generator/parser/openapi.py (2)

707-735: Consider logging exceptions instead of silently suppressing them.

The broad except Exception: pass at lines 734-735 will silently swallow any errors during forced base model generation. While this prevents one problematic schema from breaking the entire generation, it could make debugging difficult.

Consider adding a warning or debug log:

🔎 Proposed improvement for exception handling
             except Exception:  # noqa: BLE001, S110  # pragma: no cover
-                pass
+                # Schema couldn't be processed; continue with remaining refs
+                warn(f"Could not generate forced base model for {ref_path}", stacklevel=2)

737-737: Remove unused noqa directive.

Static analysis indicates the # noqa: PLR0912 directive is unnecessary since this rule is not enabled.

🔎 Proposed fix
-    def _parse_raw_impl(self) -> None:  # noqa: PLR0912
+    def _parse_raw_impl(self) -> None:
📜 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 60f7335 and d825aec.

⛔ Files ignored due to path filters (1)
  • tests/data/openapi/read_only_write_only_ref_request_response.yaml is excluded by !tests/data/**/*.yaml and included by none
📒 Files selected for processing (4)
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • tests/data/expected/main/openapi/read_only_write_only_ref_request_response.py
  • tests/main/openapi/test_main_openapi.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/data/expected/main/openapi/read_only_write_only_ref_request_response.py (1)
src/datamodel_code_generator/model/base.py (1)
  • name (839-841)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/enums.py (1)
  • ReadOnlyWriteOnlyModelType (181-189)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/openapi.py

737-737: Unused noqa directive (non-enabled: PLR0912)

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). (9)
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (10)
src/datamodel_code_generator/parser/jsonschema.py (5)

982-1016: LGTM - Well-structured variant detection logic.

The method correctly determines if a referenced schema will generate a Request or Response variant by checking that it has the relevant read-only/write-only fields AND at least one field that would remain after filtering.


1018-1046: LGTM - Correctly identifies schemas that will produce models.

The logic properly handles the edge cases where a schema with only readOnly or only writeOnly fields would not produce a base model in request-response mode.


1048-1065: LGTM - Recursive reference update with forced model tracking.

The method correctly updates data type references to point to variant models and tracks schemas that need forced base model generation.


1067-1080: LGTM - Clean field reference update implementation.

The method correctly guards against non-RequestResponse modes and updates field references to point to variant models.


1094-1095: LGTM - Proper integration of field reference updates.

The call to _update_field_refs_for_variant is correctly placed before variant model creation.

src/datamodel_code_generator/parser/openapi.py (1)

702-705: LGTM - Clean refactoring to support forced base model generation.

The separation of _parse_raw_impl and _generate_forced_base_models is well-structured.

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

4424-4444: LGTM! Well-documented test for issue #2940.

This test properly exercises the readOnly/writeOnly $ref handling in request-response mode. The docstring clearly explains the expected behavior:

  • Variant references when the referenced schema generates Request/Response variants
  • Forced base model generation when schemas contain only readOnly or writeOnly fields

The test structure follows established patterns and should effectively validate the fix.

tests/data/expected/main/openapi/read_only_write_only_ref_request_response.py (3)

10-19: LGTM! Correct variant references in parent models.

The parent models (ParentWithMixedChildRequest, ParentWithChildListRequest) correctly reference the ChildMixedRequest variant rather than a base Child model. This demonstrates the fix working as intended—when a referenced schema generates Request/Response variants, parent schemas use the appropriate variant reference.


22-27: LGTM! Forced base models for single-direction schemas.

These base models (ChildOnlyReadOnly, ChildOnlyWriteOnly) correctly lack Request/Response suffixes. This aligns with the expected behavior described in the test: when a schema contains only readOnly or only writeOnly fields, the generator forces creation of a base model since no variants would otherwise be produced.


30-35: LGTM! Correct single-variant generation with base model references.

The asymmetric variant generation is correct:

  • ParentWithOnlyReadOnlyChildRequest (only Request variant) references ChildOnlyReadOnly base model
  • ParentWithOnlyWriteOnlyChildResponse (only Response variant) references ChildOnlyWriteOnly base model

This demonstrates the fix properly handles the case where referenced schemas generate forced base models—the parent variants use those base model references instead of searching for non-existent variant types.

@koxudaxi koxudaxi force-pushed the fix/read-only-write-only-ref-request-response branch from d825aec to 3aaf118 Compare January 6, 2026 16:58
@koxudaxi koxudaxi force-pushed the fix/read-only-write-only-ref-request-response branch from 3aaf118 to 8358236 Compare January 6, 2026 17:00
@codecov
Copy link

codecov bot commented Jan 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (d1d6f4f) to head (d991965).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##              main     #2942    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files           92        94     +2     
  Lines        16989     17686   +697     
  Branches      1979      2037    +58     
==========================================
+ Hits         16989     17686   +697     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

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.

@koxudaxi koxudaxi merged commit e57ebd2 into main Jan 6, 2026
38 checks passed
@koxudaxi koxudaxi deleted the fix/read-only-write-only-ref-request-response branch January 6, 2026 18:17
@github-actions
Copy link
Contributor

github-actions bot commented Jan 6, 2026

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR is a bug fix for $ref handling in request-response mode with readOnly/writeOnly schemas. The changes improve correctness rather than breaking existing functionality:

  1. Code Generation Changes: The changes fix incorrect behavior where $ref references in Request/Response variant models could point to non-existent or incorrect models. The fix ensures references correctly point to variant models (e.g., ChildMixedRequest instead of ChildMixed) and generates base models for schemas that only contain readOnly/writeOnly fields when needed. This is corrective behavior - previous output was buggy.

  2. New Feature Flag: The read_only_write_only attribute added to JsonSchemaFeatures is an internal addition that doesn't affect external API or behavior by default.

  3. Strict Mode Warnings: New warnings for using readOnly/writeOnly in Draft 4/6 strict mode are informational and don't break functionality - they correctly inform users about schema version incompatibilities.

Users who were affected by issue #2940 (broken $ref handling) will see improved, correct output. The change doesn't remove functionality or change existing valid behavior - it fixes broken behavior. No CLI options, Python API, or template interfaces changed.


This analysis was performed by Claude Code Action

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.

read-only-write-only-model-type breaks with refs

2 participants