Skip to content

Cache JSON Schema ref facts#3472

Merged
koxudaxi merged 2 commits into
mainfrom
cache-ref-data-type-facts
Jun 22, 2026
Merged

Cache JSON Schema ref facts#3472
koxudaxi merged 2 commits into
mainfrom
cache-ref-data-type-facts

Conversation

@koxudaxi

@koxudaxi koxudaxi commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Performance

    • Improved JSON Schema $ref handling by reusing cached type facts from previously validated reference targets.
    • Added memoization for resolving local $ref paths, avoiding repeated path resolution work during parsing.
  • Tests

    • Added coverage to confirm cached $ref facts are reused when available, and that fallback loading still occurs when they are not.
    • Added checks that repeated local reference path resolutions benefit from memoization.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 98e57fdb-7072-4a13-a68e-cc1b34ba5d74

📥 Commits

Reviewing files that changed from the base of the PR and between a16e669 and 27adfb4.

📒 Files selected for processing (1)
  • tests/parser/test_jsonschema.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/parser/test_jsonschema.py

📝 Walkthrough

Walkthrough

Adds _local_ref_path_cache and _cache_ref_data_type_facts() to JsonSchemaParser, memoizing resolved local ref paths and per-resolved_ref data type facts. Cache population is wired into _parse_raw_or_validated_obj() and _parse_file(). _load_ref_schema_object() is refactored to use a new _get_ref_raw_schema() helper. New tests cover both cached and uncached code paths.

Changes

$ref caching and ref-loading refactor

Layer / File(s) Summary
Cache fields and _cache_ref_data_type_facts helper
src/datamodel_code_generator/parser/jsonschema.py
Declares _local_ref_path_cache on the parser instance and introduces _cache_ref_data_type_facts() to write x-python-import and strict-nullable optionality facts into _ref_data_type_facts.
Extract _get_ref_raw_schema() and update _load_ref_schema_object()
src/datamodel_code_generator/parser/jsonschema.py
Moves remote/local document lookup and JSON-pointer traversal into _get_ref_raw_schema(), then updates _load_ref_schema_object() to call that helper before validating the schema.
Memoize _resolve_local_ref_path()
src/datamodel_code_generator/parser/jsonschema.py
Updates _resolve_local_ref_path() to return a previously cached path from _local_ref_path_cache and store the result on first resolution.
Wire cache population into parse pipeline
src/datamodel_code_generator/parser/jsonschema.py
Calls _cache_ref_data_type_facts() after validation in _parse_raw_or_validated_obj(), after root object validation, and after each named-definition validation in _parse_file().
Tests for cached and uncached ref-resolution paths
tests/parser/test_jsonschema.py
Three new tests: verifies _load_ref_schema_object is skipped on cache hit after parse(); asserts loader is called once on cache miss via direct get_ref_data_type; confirms Path.resolve is not repeated on second _resolve_local_ref_path call.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • koxudaxi/datamodel-code-generator#3301: Modifies JsonSchemaParser's $ref handling to cache and reuse per-resolved_ref ref data type facts in get_ref_data_type(), the same mechanism extended in this PR.
  • koxudaxi/datamodel-code-generator#3466: Extends $ref caching and ref-validation reuse including changes to _load_ref_schema_object() and matching tests/parser/test_jsonschema.py assertions, directly overlapping with this PR's scope.
  • koxudaxi/datamodel-code-generator#3467: Refactors JsonSchemaParser._load_ref_schema_object() and populates _ref_schema_object_cache during _parse_file(), intersecting with the same code paths modified here.

Poem

🐇 Hop, hop, cache the path—
no need to tread the same math!
_local_ref_path_cache holds the key,
_ref_data_type_facts sets us free.
One resolve per road, the rabbit said,
then skip the rest and nap instead. 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Cache JSON Schema ref facts' directly and accurately summarizes the main change: adding caching mechanisms for JSON Schema reference handling and data type facts.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cache-ref-data-type-facts

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

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

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

@codspeed-hq

codspeed-hq Bot commented Jun 22, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 16.59%

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

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 11 improved benchmarks
⏩ 98 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_perf_large_models_pydantic_v2 3.6 s 3 s +20.15%
WallTime test_perf_complex_refs 2 s 1.7 s +20.06%
WallTime test_perf_multiple_files_input 3.6 s 3 s +19.55%
WallTime test_perf_duplicate_names 1,078.2 ms 911.1 ms +18.34%
WallTime test_perf_kubernetes_style_pydantic_v2 2.7 s 2.2 s +18.19%
WallTime test_perf_deep_nested 5.2 s 4.4 s +16.67%
WallTime test_perf_stripe_style_pydantic_v2 2 s 1.7 s +15.17%
WallTime test_perf_all_options_enabled 5.4 s 4.7 s +15.14%
WallTime test_perf_graphql_style_pydantic_v2 796.6 ms 697.1 ms +14.27%
WallTime test_perf_openapi_large 2.9 s 2.6 s +12.92%
WallTime test_perf_aws_style_openapi_pydantic_v2 1.9 s 1.7 s +12.33%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing cache-ref-data-type-facts (27adfb4) with main (988da55)

Open in CodSpeed

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

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (988da55) to head (27adfb4).

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #3472   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          150       150           
  Lines        32337     32375   +38     
  Branches      3774      3775    +1     
=========================================
+ Hits         32337     32375   +38     
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 Harness.
📢 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/parser/test_jsonschema.py (1)

184-188: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Make the cache-hit assertion non-vacuous.

This currently passes even if Path.resolve is never called. Assert the first invocation actually exercised resolution before checking the second call is cached.

Proposed test hardening
     parser._resolve_local_ref_path(target, "schema.json")
     first_call_count = len(calls)
+    assert first_call_count > 0
     parser._resolve_local_ref_path(target, "schema.json")

     assert len(calls) == first_call_count
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/parser/test_jsonschema.py` around lines 184 - 188, The test currently
checks that a second call to parser._resolve_local_ref_path does not increase
the call count, but it fails to verify that the first invocation actually
performed resolution and increased the call count. Add an assertion after the
first parser._resolve_local_ref_path call to confirm that len(calls) is greater
than first_call_count, then capture this new count and call
parser._resolve_local_ref_path a second time to verify the cached result does
not increase the call count further.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/parser/test_jsonschema.py`:
- Around line 184-188: The test currently checks that a second call to
parser._resolve_local_ref_path does not increase the call count, but it fails to
verify that the first invocation actually performed resolution and increased the
call count. Add an assertion after the first parser._resolve_local_ref_path call
to confirm that len(calls) is greater than first_call_count, then capture this
new count and call parser._resolve_local_ref_path a second time to verify the
cached result does not increase the call count further.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 531be4e8-b483-49eb-8507-19eb6f192566

📥 Commits

Reviewing files that changed from the base of the PR and between 988da55 and a16e669.

📒 Files selected for processing (2)
  • src/datamodel_code_generator/parser/jsonschema.py
  • tests/parser/test_jsonschema.py

@koxudaxi koxudaxi merged commit 4ddf239 into main Jun 22, 2026
61 checks passed
@koxudaxi koxudaxi deleted the cache-ref-data-type-facts branch June 22, 2026 06:26
@github-actions

Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: PR #3472 is a purely internal performance optimization that caches JSON Schema ref facts. All modified methods are private (underscore-prefixed): _load_ref_schema_object, _get_ref_raw_schema (newly extracted helper), _cache_ref_data_type_facts (new helper), _resolve_local_ref_path, _parse_raw_or_validated_obj, and _parse_file. The changes only add caching (_local_ref_path_cache, populating _ref_data_type_facts) to avoid redundant validation/path resolution work. The "deleted lines" are merely a refactor — the body of _load_ref_schema_object was relocated into the new _get_ref_raw_schema helper, preserving behavior. There are no changes to: CLI options, public Python API, default values/behavior, generated code output, Jinja2 templates, Python version support, or error handling. A new test explicitly confirms the non-cached fallback path is preserved, so existing behavior is unchanged. No breaking changes.


This analysis was performed by Claude Code Action

@github-actions

Copy link
Copy Markdown
Contributor

🎉 Released in 0.65.1

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