Skip to content

Add --use-tuple-for-fixed-items option#2756

Merged
koxudaxi merged 1 commit intomainfrom
feature/use-tuple-for-fixed-items
Dec 23, 2025
Merged

Add --use-tuple-for-fixed-items option#2756
koxudaxi merged 1 commit intomainfrom
feature/use-tuple-for-fixed-items

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 23, 2025

Fixes: #2247

Summary by CodeRabbit

Release Notes

  • New Features

    • Added --use-tuple-for-fixed-items CLI option to generate tuple types for arrays with fixed-length items arrays.
  • Documentation

    • Added comprehensive documentation for the new option, including usage examples and reference guides.
  • Tests

    • Added test coverage for tuple type generation with fixed-length arrays.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 23, 2025

Walkthrough

This PR introduces a new CLI option --use-tuple-for-fixed-items that enables generation of tuple types for fixed-length arrays in JSON Schema. The option is wired through documentation, CLI argument parsing, configuration, parser initialization across multiple parser subclasses, and JSON Schema parsing logic with a new helper method to detect fixed-length tuple patterns.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/cli-reference/index.md, docs/cli-reference/quick-reference.md, docs/cli-reference/typing-customization.md
Added documentation for new --use-tuple-for-fixed-items CLI option, including usage examples, descriptions, and index references.
CLI Argument & Metadata
src/datamodel_code_generator/arguments.py, src/datamodel_code_generator/cli_options.py
Added new --use-tuple-for-fixed-items argument to Typing customization group with action="store_true" and registered it in CLI_OPTION_META.
Core API & Configuration
src/datamodel_code_generator/__init__.py, src/datamodel_code_generator/__main__.py
Added use_tuple_for_fixed_items: bool = False parameter to generate() signature and Config model; threaded through to parser instantiation.
Parser Base & Subclasses
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/graphql.py
Added use_tuple_for_fixed_items parameter to Parser.init and forwarded through subclass constructors; introduced _is_fixed_length_tuple() helper in JsonSchemaParser to detect fixed-length arrays and conditionally suppress item constraints.
Test Data & Test Case
tests/data/expected/main/jsonschema/items_array_tuple.py, tests/main/jsonschema/test_main_jsonschema.py
Added expected output model with tuple field type and new test function test_main_jsonschema_items_array_tuple() validating tuple generation with the flag.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

safe-to-fix

Suggested reviewers

  • ilovelinux

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 describes the main change: adding a new CLI option --use-tuple-for-fixed-items. It is concise, specific, and accurately reflects the primary objective of the pull request.
Linked Issues check ✅ Passed The PR implements the core requirement from issue #2247: enabling tuple generation for fixed-length item structures. The implementation includes CLI option, parser integration, and test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the --use-tuple-for-fixed-items feature. Documentation updates, parser modifications, CLI configuration, and tests all support this single objective with no extraneous changes.
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 feature/use-tuple-for-fixed-items

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 23, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2756   +/-   ##
=======================================
  Coverage   99.47%   99.47%           
=======================================
  Files          83       83           
  Lines       12457    12474   +17     
  Branches     1487     1490    +3     
=======================================
+ Hits        12391    12408   +17     
  Misses         35       35           
  Partials       31       31           
Flag Coverage Δ
unittests 99.47% <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 23, 2025

CodSpeed Performance Report

Merging #2756 will not alter performance

Comparing feature/use-tuple-for-fixed-items (ad99fa4) with main (accc1f4)

Summary

✅ 73 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.

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 (4)
src/datamodel_code_generator/cli_options.py (1)

171-172: Doc metadata for the new option is correctly added.

The CLI_OPTION_META entry for --use-tuple-for-fixed-items under OptionCategory.TYPING keeps CLI docs in sync with argparse. Once you cut a release, you may want to fill in since_version for nicer docs, but it’s not required for correctness.

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

159-160: GraphQL parser wiring is fine; note that the flag is currently a no-op here.

Accepting and forwarding use_tuple_for_fixed_items keeps parser signatures uniform, and there’s no functional issue. Since this flag only has meaning for JSON Schema–style “items array” schemas, it currently has no effect for GraphQL inputs; consider calling that out in docs if you expect users to combine the option with GraphQL sources.

Also applies to: 263-264

tests/main/jsonschema/test_main_jsonschema.py (1)

3366-3396: New items_array_tuple test is consistent with existing patterns

The decorators, CLI doc metadata, and run_main_and_assert call mirror the existing prefix_items tests and correctly exercise --use-tuple-for-fixed-items with min_version/pydantic v2. I don’t see functional issues here. If you want the CLI docs to hint at neighboring options, you could optionally add related_options (e.g. collection flags) to the @pytest.mark.cli_doc block, but it’s not required for correctness.

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

900-906: Consider explicit None handling for clarity.

The logic correctly detects fixed-length tuples, but the chained comparison obj.minItems == obj.maxItems == len(...) relies on implicit None comparison behavior. While functionally correct (returns False when either is None), explicit None checks would improve readability and make the intent clearer.

🔎 Optional refactor for clarity
 def _is_fixed_length_tuple(self, obj: JsonSchemaObject) -> bool:
     """Check if an array field represents a fixed-length tuple."""
     if obj.prefixItems is not None and obj.items in {None, False}:
-        return obj.minItems == obj.maxItems == len(obj.prefixItems)
+        if obj.minItems is None or obj.maxItems is None:
+            return False
+        return obj.minItems == obj.maxItems == len(obj.prefixItems)
     if self.use_tuple_for_fixed_items and isinstance(obj.items, list) and obj.prefixItems is None:
-        return obj.minItems == obj.maxItems == len(obj.items)
+        if obj.minItems is None or obj.maxItems is None:
+            return False
+        return obj.minItems == obj.maxItems == len(obj.items)
     return False
📜 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 accc1f4 and ad99fa4.

⛔ Files ignored due to path filters (1)
  • tests/data/jsonschema/items_array_tuple.json is excluded by !tests/data/**/*.json and included by none
📒 Files selected for processing (13)
  • docs/cli-reference/index.md
  • docs/cli-reference/quick-reference.md
  • docs/cli-reference/typing-customization.md
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/arguments.py
  • src/datamodel_code_generator/cli_options.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/graphql.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • tests/data/expected/main/jsonschema/items_array_tuple.py
  • tests/main/jsonschema/test_main_jsonschema.py
⏰ 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.11 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (14)
docs/cli-reference/typing-customization.md (2)

24-24: LGTM!

The table entry is properly formatted and provides a clear, concise description of the new option.


3088-3139: Excellent documentation for the new feature!

The section is well-structured and provides:

  • Clear description of when tuples are generated
  • Practical usage example
  • Complete input/output demonstration showing the transformation from a fixed-length array to tuple[float, float]

The example effectively demonstrates the core use case mentioned in issue #2247.

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

12-12: LGTM!

The documentation updates correctly:

  • Increment the Typing Customization options count from 19 to 20
  • Add the new option to the alphabetical index with proper linking

Also applies to: 187-187

src/datamodel_code_generator/__main__.py (2)

436-436: LGTM!

The configuration option is properly declared with:

  • Appropriate type annotation (bool)
  • Sensible default value (False) for an opt-in feature
  • Logical placement near related array/collection options (use_unique_items_as_set)

746-746: LGTM!

The parameter is correctly passed from the config to the generate() function, following the established pattern used for other similar options.

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

46-46: LGTM!

The quick reference documentation correctly adds the new option:

  • In the Typing Customization section with proper description and link
  • In the alphabetical index at the correct position

Both entries are consistent with the existing format and link to the detailed documentation.

Also applies to: 287-287

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

736-737: New use_tuple_for_fixed_items flag is wired cleanly; please double‑check interaction with --use-unique-items-as-set.

The new constructor parameter and instance attribute are consistent with neighboring options and correctly exposed on Parser.

One thing to verify: __replace_unique_list_to_set() still converts list‑typed fields with constraints.unique_items into set when use_unique_items_as_set is enabled. For fixed‑items arrays that you now map to tuples, ensure those cases either:

  • don’t set constraints.unique_items, or
  • no longer present as is_list at this stage,

so that --use-tuple-for-fixed-items and --use-unique-items-as-set can’t silently fight over the same field.

Also applies to: 846-847

tests/data/expected/main/jsonschema/items_array_tuple.py (1)

1-11: Expected output for tuple-typed field looks correct.

The generated model header and point: tuple[float, float] annotation align with the new flag’s intent and existing expected-output style.

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

243-244: OpenAPI parser correctly propagates use_tuple_for_fixed_items.

The new flag is added to OpenAPIParser.__init__ and forwarded in the super().__init__ call in the same relative position as in the base parser, so OpenAPI component schemas and inlined schemas will honor the tuple-for-fixed-items behavior without additional changes here.

Also applies to: 347-348

src/datamodel_code_generator/arguments.py (1)

489-494: CLI flag definition is consistent with existing typing options.

--use-tuple-for-fixed-items follows the established pattern (store_true, default=None under “Typing customization”), so it should integrate cleanly with config loading and the generate() API.

src/datamodel_code_generator/__init__.py (1)

469-469: use_tuple_for_fixed_items threading through generate() looks correct

Adding use_tuple_for_fixed_items as a defaulted kwarg and forwarding it into the parser constructor is consistent with how other feature flags are wired, and keeps existing generate() callers source-compatible.

Also applies to: 724-724

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

583-583: LGTM! Parameter addition looks good.

The new use_tuple_for_fixed_items parameter is properly added to the constructor with a sensible default value (False) and correctly forwarded to the parent class initialization.

Also applies to: 686-686


1059-1061: LGTM! Constraint suppression is correctly implemented.

Suppressing minItems and maxItems constraints for fixed-length tuples is the correct behavior, as the tuple length is already determined by the number of elements in the tuple definition.


2448-2454: LGTM! Array parsing integration is correct.

The helper method is properly integrated into parse_array_fields to handle both:

  1. Legacy approach: items as a list (when flag is enabled)
  2. Modern approach: prefixItems (JSON Schema 2020-12 standard)

The is_tuple and suppress_item_constraints flags are set consistently in both cases.

@koxudaxi koxudaxi merged commit d8e2fef into main Dec 23, 2025
38 checks passed
@koxudaxi koxudaxi deleted the feature/use-tuple-for-fixed-items branch December 23, 2025 13:24
@github-actions
Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR adds a new opt-in feature via the --use-tuple-for-fixed-items CLI option and corresponding use_tuple_for_fixed_items parameter. All changes are additive with sensible defaults (False), meaning: 1) Existing CLI usage continues to work unchanged, 2) Existing Python API calls continue to work (new parameter has default value), 3) Generated code output is unchanged unless users explicitly enable the new option, 4) No template changes are required. This is a purely additive feature with no impact on existing users who don't use the new option.


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.

Is it possible define tuples instead of lists for types?

1 participant