Skip to content

Conversation

@koxudaxi
Copy link
Owner

@koxudaxi koxudaxi commented Jan 10, 2026

Fixes: #2951

Summary by CodeRabbit

Release Notes

  • New Features

    • Added --use-closed-typed-dict and --no-use-closed-typed-dict CLI options to control PEP 728 TypedDict closed/extra_items generation. Enabled by default for improved type checking; disable for compatibility with tools that don't yet support PEP 728.
  • Documentation

    • Updated CLI reference to document new TypedDict closed behavior options.
  • Tests

    • Added tests for TypedDict closed/extra_items generation behavior.

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

@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Warning

Rate limit exceeded

@koxudaxi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 6 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 3608e34 and d2d5cc4.

⛔ Files ignored due to path filters (1)
  • docs/llms-full.txt is excluded by none and included by none
📒 Files selected for processing (4)
  • docs/cli-reference/quick-reference.md
  • docs/cli-reference/typing-customization.md
  • src/datamodel_code_generator/prompt_data.py
  • tests/main/jsonschema/test_main_jsonschema.py
📝 Walkthrough

Walkthrough

The PR introduces a new CLI option --use-closed-typed-dict (with default True) to control PEP 728 closed TypedDict generation. The option is propagated through configuration classes, CLI argument parsing, documentation, and parser logic, with corresponding test coverage and expected output files.

Changes

Cohort / File(s) Summary
CLI Documentation
docs/cli-reference/index.md, docs/cli-reference/quick-reference.md, docs/cli-reference/typing-customization.md
Updated CLI reference documentation to list two new options (--use-closed-typed-dict and --no-use-closed-typed-dict) with descriptions and cross-references. Typing Customization count increased from 27 to 29 items.
Configuration Type Definitions
src/datamodel_code_generator/_types/generate_config_dict.py, src/datamodel_code_generator/_types/parser_config_dicts.py
Added use_closed_typed_dict: NotRequired[bool] field to GenerateConfigDict and ParserConfigDict TypedDicts to extend public config surface.
Configuration Classes
src/datamodel_code_generator/config.py, src/datamodel_code_generator/__main__.py
Added use_closed_typed_dict: bool = True field to GenerateConfig and ParserConfig classes, with default value propagated through main execution path.
CLI Arguments & Metadata
src/datamodel_code_generator/arguments.py, src/datamodel_code_generator/cli_options.py, src/datamodel_code_generator/prompt_data.py
Introduced new CLI option --use-closed-typed-dict with BooleanOptionalAction, added corresponding metadata entries, and extended OPTION_DESCRIPTIONS mapping with descriptions for both flag variants.
Parser Implementation
src/datamodel_code_generator/parser/base.py, src/datamodel_code_generator/parser/jsonschema.py
Assigned use_closed_typed_dict from config to parser instance attribute; added guard condition in set_additional_properties to skip PEP 728 conversion when flag is False.
Test Expected Outputs & Test Cases
tests/data/expected/main/input_model/config_class.py, tests/data/expected/main/jsonschema/typed_dict_no_closed.py, tests/main/jsonschema/test_main_jsonschema.py, tests/main/test_public_api_signature_baseline.py
Added expected TypedDict output for disabled closed mode, new test functions (test_main_typed_dict_closed, test_main_typed_dict_no_closed) with CLI doc blocks, and updated public API signature baseline.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Parser
    participant Config as Config Layer
    participant Parser as JSON Schema Parser
    participant Generator as TypedDict Generator
    
    CLI->>Config: Parse --use-closed-typed-dict flag
    Config->>Parser: Initialize with use_closed_typed_dict
    Parser->>Parser: Store flag in instance
    Parser->>Generator: Process additionalProperties
    alt use_closed_typed_dict = True
        Generator->>Generator: Apply PEP 728 closed=True
    else use_closed_typed_dict = False
        Generator->>Generator: Skip PEP 728 conversion
    end
    Generator->>Generator: Generate standard TypedDict
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • #2922: Implements underlying PEP 728 closed TypedDict support in JSON Schema parser; this PR adds the user-facing toggle to control that feature.
  • #2832: Updates public API signature baselines; this PR extends baseline signatures with the new use_closed_typed_dict parameter.

Suggested labels

enhancement, breaking-change-analyzed

Poem

🐰 A toggle hops into our typed dict den,
Closed=True by default, but control it when—
PEP 728 shines bright for modern tools,
Yet mypy waits gently by parsing rules.
One flag to rule them, old checkers and new! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% 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 accurately describes the main change: adding a new CLI option --use-closed-typed-dict to control PEP 728 TypedDict generation. It is specific, concise, and directly reflects the primary objective.
Linked Issues check ✅ Passed The PR successfully addresses issue #2951 by implementing a CLI option to control PEP 728 TypedDict generation, allowing users to disable closed TypedDict generation for mypy compatibility.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the --use-closed-typed-dict option and its documentation. No unrelated modifications detected beyond the scope of issue #2951.

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


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.

Generated by GitHub Actions
@github-actions
Copy link
Contributor

github-actions bot commented Jan 10, 2026

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

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 10, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing feature/use-closed-typed-dict-option (d2d5cc4) with main (98f3a48)

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

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/datamodel_code_generator/__main__.py (1)

124-127: Fix generate_cli_command() for use_closed_typed_dict=false by extending BOOLEAN_OPTIONAL_OPTIONS.
Without this, datamodel-codegen --generate-cli-command will omit --no-use-closed-typed-dict even when config sets it to false (and CLI default is True), producing the wrong command.

Proposed fix
 BOOLEAN_OPTIONAL_OPTIONS: frozenset[str] = frozenset({
     "use_specialized_enum",
     "use_standard_collections",
+    "use_closed_typed_dict",
 })

Also applies to: 569-570, 1011-1016

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

1303-1325: The early-return when use_closed_typed_dict is disabled breaks Pydantic model generation.

The set_additional_properties() early-return (lines 1313–1314) prevents writing any additionalProperties* keys to extra_template_data when the flag is disabled. However, Pydantic v1 and v2 models rely on the additionalProperties key to configure their config_extra behavior—both pydantic_v2/base_model.py:317 and pydantic/base_model.py:391 read this key to decide whether to allow extra fields. When use_closed_typed_dict=False, Pydantic models no longer see this metadata and cannot respect schema constraints like additionalProperties: true.

The early-return should only skip TypedDict-specific logic (e.g., setting additionalPropertiesType and use_typeddict_backport), but should still set the base additionalProperties boolean so other model types remain unaffected.

🤖 Fix all issues with AI agents
In @docs/cli-reference/typing-customization.md:
- Around line 1749-1801: The docs duplicate two sections for the flags
--use-closed-typed-dict and --no-use-closed-typed-dict with identical examples;
update both sections so they clearly state the default and show distinct
examples: in the --use-closed-typed-dict section state it is the default and
show a TypedDict declaration including closed=True (or PEP 728 extra_items
usage), and in the --no-use-closed-typed-dict section show the Compatible/mypy
example without closed=True (i.e., no closed parameter), and fix the usage
snippets to actually include the flag being documented (use the full command
including --use-closed-typed-dict or --no-use-closed-typed-dict). Ensure both
occurrences of these sections (the current block and the similar block around
lines 3276-3328) are updated the same way.
- Around line 1758-1764: Update the usage example for the datamodel-codegen
command to show the documented flag by adding --no-use-closed-typed-dict to the
example invocation so it reads datamodel-codegen --input schema.json
--output-model-type typing.TypedDict --no-use-closed-typed-dict; ensure the tip
block and the numbered note (1) still match the description of the
--no-use-closed-typed-dict option.
🧹 Nitpick comments (3)
src/datamodel_code_generator/arguments.py (1)

603-609: Consider clarifying default behavior in help text.

The help text doesn't explicitly state whether PEP 728 TypedDict generation is enabled by default. While the phrasing "Use --no-use-closed-typed-dict for type checkers..." implies the positive flag is default, making this explicit would improve clarity.

♻️ Suggested enhancement
 typing_options.add_argument(
     "--use-closed-typed-dict",
-    help="Generate TypedDict with PEP 728 closed=True/extra_items for additionalProperties constraints. "
+    help="Generate TypedDict with PEP 728 closed=True/extra_items for additionalProperties constraints (default: enabled). "
     "Use --no-use-closed-typed-dict for type checkers that don't yet support PEP 728 (e.g., mypy).",
     action=BooleanOptionalAction,
     default=None,
 )
tests/main/jsonschema/test_main_jsonschema.py (2)

4262-4273: Make the CLI-doc example deterministic by including the same target/version and (optionally) explicit flag.

Right now the cli_doc example only passes --output-model-type typing.TypedDict, but the actual test/golden output appears to be tied to --target-python-version 3.10 (and implicitly to the default for --use-closed-typed-dict). If defaults change, the doc snippet can drift from the asserted output.

Proposed patch
 @pytest.mark.cli_doc(
     options=["--use-closed-typed-dict", "--no-use-closed-typed-dict"],
@@
     input_schema="jsonschema/typed_dict_closed.json",
-    cli_args=["--output-model-type", "typing.TypedDict"],
+    cli_args=[
+        "--output-model-type",
+        "typing.TypedDict",
+        "--target-python-version",
+        "3.10",
+        # Optional: make the doc example independent of the default
+        # "--use-closed-typed-dict",
+    ],
     golden_output="jsonschema/typed_dict_closed.py",
 )

4316-4336: Good coverage for disabling closed=True, but consider also covering the extra_items suppression path.

test_main_typed_dict_no_closed validates the additionalProperties: false -> closed=True case. If typed_dict_extra_items.json exercises the additionalProperties: {type: ...} -> extra_items=... path, a sibling test (or parametrization) would ensure --no-use-closed-typed-dict disables both PEP 728 outputs, not just closed=True.

📜 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 98f3a48 and 3608e34.

⛔ Files ignored due to path filters (1)
  • docs/llms-full.txt is excluded by none and included by none
📒 Files selected for processing (16)
  • docs/cli-reference/index.md
  • docs/cli-reference/quick-reference.md
  • docs/cli-reference/typing-customization.md
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dicts.py
  • src/datamodel_code_generator/arguments.py
  • src/datamodel_code_generator/cli_options.py
  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/prompt_data.py
  • tests/data/expected/main/input_model/config_class.py
  • tests/data/expected/main/jsonschema/typed_dict_no_closed.py
  • tests/main/jsonschema/test_main_jsonschema.py
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/data/expected/main/jsonschema/typed_dict_no_closed.py (1)
src/datamodel_code_generator/model/typed_dict.py (1)
  • TypedDict (50-177)
⏰ 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). (10)
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (12)
tests/data/expected/main/jsonschema/typed_dict_no_closed.py (1)

1-14: Expected “no closed TypedDict” fixture looks correct. The generated ClosedModel(TypedDict) omits closed=True / extra_items, aligning with --no-use-closed-typed-dict.

src/datamodel_code_generator/_types/parser_config_dicts.py (1)

111-112: Config surface addition is consistent (ParserConfigDict.use_closed_typed_dict).

src/datamodel_code_generator/_types/generate_config_dict.py (1)

116-118: Config surface addition is consistent (GenerateConfigDict.use_closed_typed_dict).

tests/main/test_public_api_signature_baseline.py (1)

136-138: Baseline signatures updated appropriately (new kwarg with default True).

Also applies to: 268-270

tests/data/expected/main/input_model/config_class.py (1)

194-196: Expected generated config fixture updated correctly (new use_closed_typed_dict).

docs/cli-reference/quick-reference.md (1)

39-50: Documentation anchors are properly defined for both TypedDict flags.
The quick-reference updates correctly link to existing sections in typing-customization.md for both --no-use-closed-typed-dict and --use-closed-typed-dict, and the flags appear consistently across the alphabetical index and table.

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

922-924: Parser wiring is correct: Flag properly stored on Parser instance and gated throughout the JSON Schema handler.

The flag is wired from CLI → __main__.py instantiation → stored at base.py:922 → used in jsonschema.py:1313 to gate PEP 728 behavior (closed=True / extra_items=X) based on additionalProperties. Downstream use in model/typed_dict.py confirms the pattern for generating closed TypedDicts when the flag is enabled.

docs/cli-reference/index.md (1)

12-12: Keep doc counts/anchors in sync with generated CLI docs/tests.
The updated “29” count and new anchors look consistent; please ensure the referenced anchors exist in docs/cli-reference/typing-customization.md and that the auto-generated docs tests still pass.

Also applies to: 136-137, 190-190

src/datamodel_code_generator/cli_options.py (1)

206-207: CLI docs metadata additions look consistent.
No concerns here beyond ensuring tests/cli_doc/test_cli_options_sync.py remains green.

src/datamodel_code_generator/config.py (1)

152-152: Config surface addition looks good; please confirm end-to-end wiring.
Given this affects Python typing features (PEP 728), ensure parser/generator wiring and public API signature tests cover the new flag.

Also applies to: 290-290

src/datamodel_code_generator/__main__.py (1)

1011-1016: use_closed_typed_dict is correctly propagated to generate().

The parameter is properly defined in GenerateConfigDict and accepted by the generate() function through its **options: Unpack[GenerateConfigDict] signature.

src/datamodel_code_generator/prompt_data.py (1)

81-81: Verify consistency with auto-generation process.

The file header indicates this is auto-generated and should not be edited manually (lines 1-3), but this PR directly modifies it. Additionally, both --no-use-closed-typed-dict and --use-closed-typed-dict share identical descriptions, which doesn't help users understand the difference or default behavior.

Consider regenerating this file using python scripts/build_prompt_data.py after updating the source cli_doc markers, and differentiate the descriptions to indicate which is the default behavior (e.g., "--use-closed-typed-dict (default): Generate..." vs "--no-use-closed-typed-dict: Disable...").

Also applies to: 116-116

@codecov
Copy link

codecov bot commented Jan 10, 2026

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #2956   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           94        94           
  Lines        17726     17738   +12     
  Branches      2037      2038    +1     
=========================================
+ Hits         17726     17738   +12     
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 aa088d6 into main Jan 10, 2026
40 checks passed
@koxudaxi koxudaxi deleted the feature/use-closed-typed-dict-option branch January 10, 2026 08:17
@github-actions
Copy link
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: PR #2956 adds the --use-closed-typed-dict/--no-use-closed-typed-dict CLI options to control PEP 728 TypedDict generation (closed=True/extra_items). The default value is True, which preserves the existing behavior that was introduced in PR #2922. This PR does not change the default behavior - it only adds a way to opt-out of PEP 728 TypedDict generation for users who need compatibility with type checkers that don't support PEP 728 (e.g., mypy). Since the default behavior remains unchanged (PEP 728 closed TypedDict is still generated by default), this is not a breaking change. It's a backward-compatible feature addition that gives users more control.


This analysis was performed by Claude Code Action

@jacopoabramo
Copy link

Hi @koxudaxi , thanks for resolving this issue this quickly. Just for my own knowledge when do you expect to release these changes? Thanks in advance.

@github-actions
Copy link
Contributor

🎉 Released in 0.53.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.

Question: optionally suppress generation of closed=True for typed dictionaries

3 participants