Skip to content

Refactor config handling and add CLI TypedDicts#2830

Closed
koxudaxi wants to merge 33 commits intomainfrom
refactor-config-cli-typed-dicts
Closed

Refactor config handling and add CLI TypedDicts#2830
koxudaxi wants to merge 33 commits intomainfrom
refactor-config-cli-typed-dicts

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 27, 2025

Summary by CodeRabbit

  • New Features

    • Config-driven public API: pass rich config objects or config dicts to generation and parser commands; added four config profiles for pyproject setup and TypedDict-based config types for better IDE/type support.
  • Refactor

    • Consolidated many keyword options into unified config objects across CLI and parser flows while preserving option-based usage.
  • Tests

    • Expanded tests to cover config-object and mixed usage paths and public API behavior.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 27, 2025

📝 Walkthrough

Walkthrough

Refactors the project to a config-driven architecture: adds Pydantic config models (GenerateConfig, ParserConfig, ParseConfig, CliConfigSchema), generates TypedDicts, and updates generate(), CLI, and Parser constructors to accept/validate config objects or config dicts. Tests and tooling updated to support generation and validation of config types.

Changes

Cohort / File(s) Summary
Project metadata & tooling
pyproject.toml, tox.ini
Added pyproject profiles for TypedDict generation and new tox envs (config-types, lint); expanded run.omit to cover additional _types paths.
Config models & typed dicts
src/datamodel_code_generator/config.py, src/datamodel_code_generator/_types/*
src/datamodel_code_generator/_types/__init__.py, .../generate_config_dict.py, .../parser_config_dict.py, .../parse_config_dict.py, .../cli_config_dict.py
Introduces Pydantic models: GenerateConfig, ParserConfig, ParseConfig, CliConfigSchema; adds corresponding TypedDict modules and export aliases; implements _rebuild_config_models and helpers to synthesize parser/parse configs from GenerateConfig.
Public API surface / entrypoints
src/datamodel_code_generator/__init__.py, src/datamodel_code_generator/__main__.py
generate() now accepts GenerateConfig or a config-dict (Unpack[GenerateConfigDict]) via overloads; exports new config types; CLI Config now inherits from GenerateConfig and provides to_generate_config(); lazy __getattr__ added for runtime config/type exposure.
Parser core & subclasses
src/datamodel_code_generator/parser/base.py, .../graphql.py, .../jsonschema.py, .../openapi.py
Parser constructors and parse flows refactored to accept ParserConfig or **options: Unpack[ParserConfigDict]; mutual-exclusivity checks added; internal ParseConfig renamed/standardized to ParseSettings; parsing pipeline now propagates a single validated settings object.
Tests
tests/main/test_main_general.py, tests/main/test_public_api_direct.py, tests/main/test_public_api_signature_baseline.py
Adds/updates tests for config-driven APIs: validate config object/dict acceptance, mutual exclusivity, CLI-to-config conversion, and updated public-signature baselines; exercises parser subclasses and generate() with both config objects and dicts.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant generate as generate()
    participant GenCfg as GenerateConfig
    participant Parser as Parser
    participant ParseCfg as ParserConfig / ParseSettings
    rect `#dfeef7`
      Note over User,GenCfg: Config-driven invocation
      User->>+generate: generate(input, config=cfg OR **options)
      generate->>GenCfg: validate/construct GenerateConfig (model_validate/model_dump)
      activate GenCfg
      GenCfg-->>generate: validated GenerateConfig
      deactivate GenCfg
      generate->>Parser: Parser(source, config=ParserConfig._from_generate_config(cfg))
      Parser->>ParseCfg: build ParserConfig / ParseSettings
      activate ParseCfg
      ParseCfg-->>Parser: ParseSettings
      deactivate ParseCfg
      Parser->>Parser: parse(config=ParseSettings)
      Parser-->>generate: Result (modules/output)
      generate-->>-User: write output (config.output / encoding)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

breaking-change-analyzed

Suggested reviewers

  • ilovelinux

"🐇 I hopped through code to mend the flow,
One config to rule them, neat in a row.
Parsers and CLI now sip from the same cup,
TypedDicts in pockets — compile, fill up!
Hooray for fewer args, a tidy new show."

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.41% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Refactor config handling and add CLI TypedDicts' clearly summarizes the main changes: refactoring of configuration handling throughout the codebase and addition of TypedDict definitions for CLI configuration.
✨ 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 refactor-config-cli-typed-dicts

📜 Recent 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 6ae0294 and 9273324.

📒 Files selected for processing (2)
  • tests/main/test_main_general.py
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/main/test_main_general.py (7)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • GenerateConfig (49-169)
src/datamodel_code_generator/config.py (6)
  • GenerateConfig (85-217)
  • ParserConfig (390-568)
  • Config (92-96)
  • Config (227-231)
  • Config (397-401)
  • Config (578-582)
src/datamodel_code_generator/parser/base.py (2)
  • Parser (684-3107)
  • parse (3008-3107)
src/datamodel_code_generator/parser/graphql.py (1)
  • GraphQLParser (60-502)
src/datamodel_code_generator/parser/jsonschema.py (2)
  • JsonSchemaParser (520-3289)
  • Config (368-373)
src/datamodel_code_generator/parser/openapi.py (1)
  • OpenAPIParser (165-748)
src/datamodel_code_generator/__init__.py (4)
  • Error (298-307)
  • generate (452-457)
  • generate (461-465)
  • generate (468-835)
⏰ 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). (11)
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.11 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (11)
tests/main/test_main_general.py (7)

5-6: LGTM!

The new imports are well-organized and appropriate for the added test coverage. Standard library imports (io, json) are correctly placed, and the new config/parser imports align with the PR's config-driven architecture changes.

Also applies to: 27-27, 29-31, 35-35


109-133: LGTM!

These tests provide good coverage for the Config class's file field validation, covering the key scenarios: None values, dict input, file-like objects (StringIO), and invalid file paths.


135-151: LGTM!

The test correctly uses monkeypatching to inject invalid data (non-string keys) into extra_template_data and verifies that the main function properly rejects it with an error exit.


153-194: LGTM!

Good coverage for aliases handling:

  • Invalid aliases file rejection (nested dict with non-string values)
  • Pydantic v1 compatibility branch coverage with appropriate skip logic
  • Valid aliases mapping file acceptance

196-206: LGTM!

The test correctly validates that custom_formatters_kwargs file with invalid nested values (non-string) is rejected with an error exit.


232-271: LGTM!

These tests effectively validate the mutual exclusivity between config and individual options:

  • generate() properly rejects combined usage with clear error message
  • generate() accepts config as a dict mapping
  • Parser.__init__ enforces the same constraint using a minimal DummyParser subclass

273-357: LGTM!

Excellent test coverage for the config-driven parser initialization across all parser types:

  • Base Parser.parse() method correctly validates config/options exclusivity
  • GraphQLParser, JsonSchemaParser, and OpenAPIParser all follow the same pattern
  • Each parser has appropriate attribute assertions to verify successful initialization
tests/main/test_public_api_signature_baseline.py (4)

8-8: LGTM!

Import updates align with the new config-driven architecture. The imports now reference GenerateConfigDict and ParserConfigDict for TypedDict-based signature validation.

Also applies to: 10-10, 16-17


25-47: LGTM!

The TYPE_CHECKING block is well-organized with comprehensive type imports needed for the baseline signature definitions. The separation of runtime and type-only imports follows best practices.


184-186: LGTM!

The baseline parser updates correctly reflect the current implementation's default values and type annotations.

Also applies to: 232-232


305-328: LGTM!

The updated tests effectively validate that GenerateConfigDict and ParserConfigDict TypedDicts maintain API compatibility with the baseline signatures. The NotRequired[...] wrapper stripping logic correctly handles the TypedDict representation of optional parameters.


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
Copy Markdown
Contributor

github-actions Bot commented Dec 27, 2025

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

Comment thread src/datamodel_code_generator/__init__.py Fixed
Comment thread src/datamodel_code_generator/config.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/__main__.py Dismissed
Comment thread src/datamodel_code_generator/config.py Fixed
Comment thread src/datamodel_code_generator/config.py Fixed
Comment thread src/datamodel_code_generator/config.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 27, 2025

CodSpeed Performance Report

Merging #2830 will not alter performance

Comparing refactor-config-cli-typed-dicts (9273324) with main (e4394af)

⚠️ 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
⏩ 98 skipped1

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

🧹 Nitpick comments (10)
src/datamodel_code_generator/parser/graphql.py (2)

92-115: Config-driven __init__ wiring looks solid

The mutual exclusivity check, model_validate(ParserConfig, ...) usage, and delegation to super().__init__(source=source, config=config) all look consistent with the new config pattern and should keep GraphQLParser aligned with the base parser behavior. The post-init assignment of self.use_standard_collections from config is redundant because Parser already sets it, but it's harmless; you could drop it later for clarity if desired.


102-110: Ruff: unused # noqa: PLC0415 on local ParserConfig import

Ruff reports this # noqa: PLC0415 as unused (rule not enabled). You can either remove the directive here or enable PLC0415 in your Ruff config if you intend to keep suppressing it.

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

181-189: Ruff: unused # noqa: PLC0415 on local ParserConfig import

Ruff flags the # noqa: PLC0415 here as unused. Consider removing it (or enabling PLC0415 in Ruff) to keep linter suppressions meaningful.

src/datamodel_code_generator/__init__.py (2)

885-899: *Consider exporting the ConfigDict types in __all__ for a fully public surface

__getattr__ exposes GenerateConfigDict, ParserConfigDict, and ParseConfigDict, but they aren’t listed in __all__. If you intend these TypedDicts to be part of the public API (as implied by the new design), adding them to __all__ would make their exposure consistent with the config models and help users relying on from datamodel_code_generator import *.

Possible `__all__` extension
 __all__ = [
@@
-    "GenerateConfig",
+    "GenerateConfig",
+    "GenerateConfigDict",
@@
-    "ParseConfig",
-    "ParserConfig",
+    "ParseConfig",
+    "ParseConfigDict",
+    "ParserConfig",
+    "ParserConfigDict",

74-75: Ruff: several unused # noqa suppressions

Ruff reports some of these # noqa comments (e.g., # noqa: E402 on the is_pydantic_v2 import and # noqa on the generate definition) as unused because those codes aren’t enabled. You can trim them back to only the active rules to keep the file’s linter state tidy.

src/datamodel_code_generator/__main__.py (2)

1099-1133: Silent failure on malformed extra_template_data / aliases / custom_formatters_kwargs

The additional type checks for extra_template_data, aliases, and custom_formatters_kwargs are good, but on failure they currently just return Exit.ERROR without any diagnostic output. That can make it hard for users to understand what went wrong when a pyproject or CLI value is mis-typed.

Consider emitting a brief error message to stderr indicating which option was invalid before returning Exit.ERROR.


42-43: Ruff: unused # noqa suppressions

Ruff reports some of the # noqa comments here (e.g., # noqa: TC003 on the Mapping, Sequence import and # noqa: N805 on validators) as unused for your current configuration. Trimming these back to only the active rules will keep the file a bit cleaner.

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

2792-2836: _prepare_parse_config() and ParseSettings cleanly separate parse-time concerns

_prepare_parse_config() now returns a ParseSettings NamedTuple that bundles with_import, use_deferred_annotations, code_formatter, module_split_mode, and all-exports settings. That keeps parse-time behavior (imports, formatting, exports) independent of the full ParseConfig model while preserving the existing logic for deferred annotations and from __future__ imports.

If you ever need to surface more parse-time knobs, extending ParseSettings instead of threading additional parameters will keep this pattern scalable.


699-707: Ruff: unused # noqa suppressions around imports and signatures

Ruff indicates some of the # noqa directives here (e.g., on the local ParserConfig import and the parse/__init__ complexity codes) are unused with your current linter configuration. Cleaning these up (or enabling the corresponding rules) would make it easier to spot meaningful suppressions.

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

83-83: Consider making ParseResult more specific.

The ParseResult type is defined as tuple[Any, Any, Any, Any, Any, Any], which provides no type safety. If this represents a URL parse result (as suggested by the name and its usage in line 159 for the url field), consider using urllib.parse.ParseResult directly or at minimum documenting what each position represents.

Example improvement

If this represents urllib.parse.ParseResult, you could use:

from urllib.parse import ParseResult as UrlParseResult
ParseResult: TypeAlias = UrlParseResult

Or if maintaining compatibility with the tuple form is required, at least document it:

# ParseResult mirrors urllib.parse.ParseResult: (scheme, netloc, path, params, query, fragment)
ParseResult: TypeAlias = tuple[Any, Any, Any, Any, Any, Any]
📜 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 7c248a9 and c0f976c.

📒 Files selected for processing (15)
  • pyproject.toml
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/_types/__init__.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/config.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/main/test_main_general.py
  • tox.ini
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/__init__.py
🧬 Code graph analysis (6)
src/datamodel_code_generator/config.py (4)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
  • DataclassArguments (35-45)
  • GenerateConfig (104-226)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
  • ConfigDict (29-55)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (22-29)
src/datamodel_code_generator/parser/openapi.py (3)
src/datamodel_code_generator/util.py (3)
  • model_copy (275-279)
  • model_dump (254-258)
  • model_validate (261-265)
src/datamodel_code_generator/parser/base.py (1)
  • parse (3105-3199)
src/datamodel_code_generator/config.py (2)
  • ParserConfig (593-713)
  • ParserConfigDict (197-309)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
src/datamodel_code_generator/enums.py (15)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • GraphQLScope (155-158)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • StrictTypes (199-206)
  • UnionMode (192-196)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (324-454)
src/datamodel_code_generator/_types/parse_config_dict.py (2)
src/datamodel_code_generator/enums.py (3)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • ModuleSplitMode (172-178)
src/datamodel_code_generator/config.py (1)
  • ParseConfig (716-733)
src/datamodel_code_generator/parser/jsonschema.py (4)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (67-179)
src/datamodel_code_generator/config.py (2)
  • ParserConfig (593-713)
  • ParserConfigDict (197-309)
src/datamodel_code_generator/util.py (2)
  • model_validate (261-265)
  • model_copy (275-279)
src/datamodel_code_generator/format.py (1)
  • DatetimeClassType (50-57)
src/datamodel_code_generator/_types/cli_config_dict.py (2)
src/datamodel_code_generator/enums.py (15)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • StrictTypes (199-206)
  • TargetPydanticVersion (181-189)
  • UnionMode (192-196)
src/datamodel_code_generator/config.py (1)
  • CliConfigSchema (457-590)
🪛 GitHub Actions: Lint
src/datamodel_code_generator/config.py

[error] 51-51: Ruff: Do not catch blind exception: Exception (BLE001) in fallback for minimal installs


[error] 331-333: D106 Missing docstring in public nested class


[error] 464-466: D106 Missing docstring in public nested class


[error] 600-602: D106 Missing docstring in public nested class


[error] 723-725: D106 Missing docstring in public nested class


[error] 1-1: Pre-commit hooks ruff-format and ruff failed during 'prek run --all-files'.

src/datamodel_code_generator/_types/cli_config_dict.py

[warning] 1-1: ruff-format reformatted 4 files as part of pre-commit hooks; please review and commit changes.

🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

51-51: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


52-52: Do not catch blind exception: Exception

(BLE001)

src/datamodel_code_generator/__init__.py

74-74: Unused noqa directive (non-enabled: E402)

Remove unused noqa directive

(RUF100)


466-466: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


483-483: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


500-500: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


606-606: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


895-895: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/openapi.py

181-181: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__main__.py

42-42: Unused noqa directive (non-enabled: TC003)

Remove unused noqa directive

(RUF100)


175-175: Unused noqa directive (non-enabled: N805)

Remove unused noqa directive

(RUF100)


500-500: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


501-501: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


503-503: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


504-504: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


505-505: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


587-587: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


1011-1011: Unused noqa directive (non-enabled: T201)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/graphql.py

102-102: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/base.py

691-691: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


699-699: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3105-3105: Unused noqa directive (non-enabled: PLR0914)

Remove unused noqa directive

(RUF100)


3112-3112: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/jsonschema.py

534-534: Unused noqa directive (non-enabled: PLC0415)

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). (12)
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: 3.11 on Ubuntu
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (19)
tox.ini (1)

17-20: Config-types tox env wired correctly to new profiles

config-types is added to env_list and the dedicated [testenv:config-types] runs the four profile-based generation commands with dependency_groups = dev and no_default_groups = true, which is appropriate and isolated from test deps.

Also applies to: 81-89

tests/main/test_main_general.py (2)

5-7: Extra-template-data and file-based config validation tests look solid

The new tests around Config(extra_template_data=...) and the main()-level rejection of invalid extra_template_data, aliases, and custom_formatters_kwargs files exercise important edge cases (None/dict/file-like inputs, bad key/value types) without overreaching. The monkeypatch of Config.parse_obj in test_main_rejects_invalid_extra_template_data is scoped and restores behavior via the original implementation.

Also applies to: 108-132, 134-173


27-32: Config vs. individual options contract for generate()/Parser/parse() is well-covered

The tests for:

  • generate() raising on config + extra options and accepting a config mapping,
  • Parser.__init__ (via DummyParser, GraphQLParser, JsonSchemaParser, OpenAPIParser) rejecting mixed config/options but accepting dict configs, and
  • Parser.parse() rejecting mixed config/options while accepting dict configs,

give good coverage of the new config-driven API and its error messages. The use of both model instances (GenerateConfig, ParserConfig, ParseConfig) and plain dicts matches the intended flexibility.

Also applies to: 200-265, 267-325

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

11-65: Generated ParserConfig TypedDict matches config model surface

The Literal aliases and ParserConfig TypedDict fields line up with the corresponding ParserConfig/ParserConfigDict model in config.py (same option names, compatible container types like dict/list). This should be a safe, strongly-typed surface for consumers of the generated config types.

Also applies to: 67-179

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

11-20: ParseConfig TypedDict correctly reflects ParseConfig model

The Literal aliases and ParseConfig TypedDict fields (including settings_path as str | None and the all-exports/module-split options) are consistent with ParseConfig in config.py and the corresponding enums, so downstream use of these generated types should be safe.

Also applies to: 22-29

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

78-84: Config-driven JsonSchemaParser.init is consistent with new API

The new signature and body:

  • Cleanly separate config: ParserConfig | None from **options: Unpack[ParserConfigDict].
  • Enforce the “no mixing config with individual options” contract tested in test_main_general.py.
  • Accept both dict and ParserConfig instances via model_validate, and normalize a default target_datetime_class using model_copy when unset.
  • Delegate to Parser.__init__ with the resolved config, keeping the rest of the parser logic unchanged.

This aligns well with the broader config refactor and the new tests around parser initialization.

Also applies to: 523-547

pyproject.toml (1)

261-279: Profiles correctly wire config models to generated TypedDict modules

The four [tool.datamodel-codegen.profiles.*] sections point at the new GenerateConfig, ParserConfig, ParseConfig, and CliConfigSchema models and generate their TypedDict representations into the expected _types/*.py paths. This matches the new tox config-types env and keeps the TypedDicts reproducible from the single source-of-truth config models.

src/datamodel_code_generator/config.py (2)

72-195: Config models and TypedDicts provide a coherent, central config surface

The new GenerateConfigDict / GenerateConfig, ParserConfigDict / ParserConfig, and ParseConfigDict / ParseConfig pairs:

  • Mirror the existing CLI/generate options (names and defaults) closely, so behavior should remain backward compatible.
  • Use Mapping/Sequence/Path in the runtime-facing dicts and models, while the generated _types modules expose simpler dict/list/str-based TypedDicts for external consumers.
  • Are wired to Pydantic v1/v2 via is_pydantic_v2() and ConfigDict, with extra="forbid" and arbitrary_types_allowed=True, which is appropriate for these rich config objects.

The shapes look internally consistent and align with the new tests and profiles; once the small lint issues above are fixed, this should be a solid foundation for the refactored config handling.

Also applies to: 197-322, 324-455, 457-591, 593-714, 716-733


47-53: Keep the defensive noqa: PLC0415 on lazy imports

The runtime import fallback for UnionMode should keep the # noqa: PLC0415 directive even though it appears unused. This project maintains defensive noqa directives on all lazy imports (imports inside functions/methods) to prepare for potential future Ruff configuration changes that might enable the import-outside-toplevel rule.

Narrowing the exception from Exception to ImportError is a reasonable improvement:

else:
    try:
        from datamodel_code_generator.model.pydantic_v2 import UnionMode  # noqa: PLC0415
    except ImportError:  # pragma: no cover - fallback for minimal installs
        UnionMode = Any  # type: ignore[assignment]

This satisfies BLE001 while preserving the defensive noqa for future compatibility.

Likely an incorrect or invalid review comment.

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

170-193: OpenAPIParser config normalization and datetime default look correct

The new config/options handling mirrors the base Parser pattern, and the model_validate(ParserConfig, ...) calls should keep external usages backward compatible. The target_datetime_class fallback to DatetimeClassType.Awaredatetime preserves an OpenAPI-specific default while still allowing explicit overrides via ParserConfig/GenerateConfig.

If you haven't already, it’s worth double-checking older tests that relied on implicit aware datetime handling for OpenAPI to ensure they still pass with this new config-based path.

src/datamodel_code_generator/__init__.py (2)

451-492: generate(...): config-driven entrypoint is well wired; verify parse defaults

The new generate() overloads and body correctly:

  • enforce config vs options exclusivity,
  • normalize any dict-like configs via model_validate(GenerateConfig, ...), and
  • bridge into ParserConfig/ParseConfig using model_dump + field filtering.

This should preserve external behavior while centralizing all parser settings under GenerateConfig. One thing to sanity-check via tests is that the implicit defaults for with_import and format_ (now coming from ParseConfig defaults) still match the previous behavior of generate() when output is None vs a Path.


678-707: ParserConfig bridging via model_dump / model_validate looks robust

Building parser_config_data = model_dump(config) and then:

  • injecting parser-only fields (data_model_type, data_model_root_type, data_type_manager_type, dump_resolve_reference_action, base_path, remote_text_cache, default_field_extras, datetime/date targets, etc.), and
  • filtering keys against ParserConfig.model_fields / __fields__ before model_validate(ParserConfig, ...)

gives a clean separation between GenerateConfig and ParserConfig while avoiding stray keys. This should make it straightforward to extend either config model independently.

src/datamodel_code_generator/__main__.py (3)

143-188: Config subclassing GenerateConfig is a good consolidation

Making Config inherit from GenerateConfig and adding CLI-specific validators (for paths, URLs, headers, JSON files) keeps a single source of truth for configuration while still handling CLI concerns. The conditional pydantic v2 helpers (parse_obj, get_fields, model_config) look correct and should preserve v1/v2 behavior.


587-627: to_generate_config(): adapter from CLI Config to GenerateConfig looks correct

to_generate_config() cleanly:

  • starts from model_dump(self),
  • strips CLI-only keys (input, check, watch, etc.),
  • maps legacy flags use_default/force_optional onto apply_default_values_for_required_fields and force_optional_for_required_fields, and
  • injects runtime-only values (extra_template_data, aliases, custom_formatters_kwargs, output, command_line, settings_path)

before validating to GenerateConfig. This should keep existing CLI semantics while aligning with the new generate(config=...) API.

If you have coverage for combinations of use_default / force_optional and the newer flags from both CLI and pyproject, it’s worth ensuring they still behave as expected with this adapter in place.


925-945: run_generate_from_config(): streamlined hand-off to generate

The new run_generate_from_config() correctly builds a GenerateConfig via Config.to_generate_config(...) and always calls generate(input_=input_, config=generate_config), which simplifies the flow and centralizes config validation in one place. The explicit casting of extra_template_data to dict[str, dict[str, Any]] | None matches what to_generate_config() expects.

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

691-823: Parser.init: centralized ParserConfig handling looks consistent

The new __init__ signature and body:

  • enforce mutual exclusivity between config and **options,
  • normalize any dict-like configs via model_validate(ParserConfig, ...), and
  • map ParserConfig fields into instance attributes and the DataTypeManager construction,

which aligns well with the rest of the refactor. The normalization of extra_template_data to a defaultdict(dict, ...) also preserves the previous mutation-friendly behavior for template metadata.


3105-3185: parse(...): config-based entrypoint matches other config patterns

The new parse(*, config: ParseConfigModel | None = None, **options) method:

  • mirrors the same config-vs-options exclusivity and model_validate(ParseConfigModel, ...) pattern used in generate() and parser constructors,
  • pulls the needed fields (with_import, format_, settings_path, disable_future_imports, all_exports_scope, all_exports_collision_strategy, module_split_mode) out of the config, and
  • feeds them into _prepare_parse_config() and _build_module_structure().

This should remain backward compatible for callers that previously passed with_import, format_, etc., directly, while offering a structured ParseConfig-based API.

It’s worth confirming via tests that existing code which calls parse(with_import=False, format_=False, ...) still behaves as expected when those arguments are now routed through ParseConfig defaults and ParseSettings.

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

159-163: No action needed. Type difference is by design and handled correctly by Pydantic.

GenerateConfigDict uses list[str] to represent the JSON/dict input format (JSON arrays), while GenerateConfig uses set[str] for internal efficiency. Pydantic v2 automatically coerces lists to sets during model validation via model_validate(), so no explicit validator is required. This pattern is intentional and correct—aligning the types would actually break the JSON serialization design.

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

163-167: The type definitions are intentional and correctly designed. The TypedDict in cli_config_dict.py uses list[str] because it represents JSON-serializable configuration data, while the Pydantic model in config.py uses set[str] for internal use with automatic list-to-set coercion during model validation. This is a proper design pattern, not a type mismatch requiring alignment.

Likely an incorrect or invalid review comment.

Comment thread src/datamodel_code_generator/_types/cli_config_dict.py
Comment thread src/datamodel_code_generator/_types/generate_config_dict.py
Comment thread src/datamodel_code_generator/config.py
Comment thread src/datamodel_code_generator/config.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Dismissed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
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: 1

♻️ Duplicate comments (2)
src/datamodel_code_generator/_types/cli_config_dict.py (1)

1-3: Formatting issue already flagged in previous review.

Run ruff format on this file to pass CI.

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

1-3: Formatting issue already addressed in previous review.

Run ruff format on all files in src/datamodel_code_generator/_types/ to resolve the pipeline failure.

🧹 Nitpick comments (1)
src/datamodel_code_generator/_types/cli_config_dict.py (1)

83-83: ParseResult type alias may not match stdlib's ParseResult.

The generated ParseResult: TypeAlias = tuple[Any, Any, Any, Any, Any, Any] is a 6-tuple approximation of urllib.parse.ParseResult. While this works for JSON/CLI serialization, consumers expecting the actual ParseResult named tuple (with .scheme, .netloc, etc. attributes) may be surprised.

Consider adding a comment clarifying this is a serialization-compatible representation, not the actual urllib.parse.ParseResult.

📜 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 c0f976c and 23515e6.

📒 Files selected for processing (6)
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/config.py
  • tests/main/test_main_general.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • tests/main/test_main_general.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
🧬 Code graph analysis (2)
src/datamodel_code_generator/config.py (5)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
  • DataclassArguments (35-45)
  • GenerateConfig (104-226)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • DataclassArguments (17-27)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
  • ConfigDict (29-55)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/__main__.py (1)
  • Config (143-627)
src/datamodel_code_generator/_types/cli_config_dict.py (3)
src/datamodel_code_generator/enums.py (15)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • StrictTypes (199-206)
  • TargetPydanticVersion (181-189)
  • UnionMode (192-196)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/config.py (1)
  • CliConfigSchema (467-602)
🪛 GitHub Actions: Lint
src/datamodel_code_generator/_types/parser_config_dict.py

[error] 1-1: ruff-format reformatted 4 files. Commit the changes or re-run the pipeline.

src/datamodel_code_generator/_types/generate_config_dict.py

[error] 1-1: ruff-format reformatted 4 files. Commit the changes or re-run the pipeline.

src/datamodel_code_generator/_types/cli_config_dict.py

[error] 1-1: ruff-format reformatted 4 files. Commit the changes or re-run the pipeline.

⏰ 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). (13)
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: 3.13 on Ubuntu
  • GitHub Check: 3.12 on Ubuntu
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (10)
src/datamodel_code_generator/config.py (7)

80-203: Well-structured TypedDict for generate configuration.

GenerateConfigDict comprehensively covers all generation options with appropriate optional typing via total=False. The field types align with the corresponding GenerateConfig BaseModel.


205-318: ParserConfigDict is comprehensive and well-typed.

The TypedDict covers parser initialization options thoroughly. Types are consistent with ParserConfig BaseModel fields.


320-330: ParseConfigDict is concise and correctly defined.

Covers the parse-time options appropriately with optional fields.


332-465: GenerateConfig BaseModel is well-implemented with proper v1/v2 compatibility.

The Pydantic v1/v2 handling pattern using is_pydantic_v2() is correct. The nested Config class now includes a docstring (addressing D106). Default values are sensible and consistent with the TypedDict counterpart.


467-603: CliConfigSchema properly extends configuration for CLI usage.

Includes CLI-specific fields (input, check, debug, watch, etc.) alongside shared configuration. The v1/v2 compatibility pattern is consistent.


605-728: ParserConfig provides comprehensive parser initialization options.

Includes type-based fields (data_model_type, data_type_manager_type, etc.) with proper defaults pointing to pydantic model types. The structure is sound.


730-749: ParseConfig is minimal and correctly scoped.

Contains only parse-time options with sensible defaults. The structure is clean.

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

67-179: ParserConfig TypedDict is comprehensive and correctly typed.

All fields use NotRequired appropriately for optional configuration. The type aliases reference the Literal definitions at the top of the file consistently.

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

104-229: CliConfigSchema TypedDict is correctly structured.

All CLI configuration options are present with appropriate NotRequired wrappers. Field types use the Literal-based type aliases defined above, ensuring type safety.

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

104-226: GenerateConfig TypedDict is comprehensive and correctly structured.

All generation options are represented with proper NotRequired typing. The intentional type conversions (e.g., Pathstr, setlist) for JSON/CLI serialization compatibility are appropriate for this generated typing surface.

Comment thread src/datamodel_code_generator/_types/parser_config_dict.py Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 27, 2025

Codecov Report

❌ Patch coverage is 99.56850% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.48%. Comparing base (45fac78) to head (6ae0294).

Files with missing lines Patch % Lines
tests/main/test_public_api_direct.py 94.33% 0 Missing and 3 partials ⚠️
src/datamodel_code_generator/parser/base.py 99.31% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2830      +/-   ##
==========================================
- Coverage   99.52%   99.48%   -0.04%     
==========================================
  Files          90       92       +2     
  Lines       13999    14710     +711     
  Branches     1668     1719      +51     
==========================================
+ Hits        13932    14634     +702     
- Misses         36       39       +3     
- Partials       31       37       +6     
Flag Coverage Δ
unittests 99.48% <99.56%> (-0.04%) ⬇️

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.

Comment thread src/datamodel_code_generator/config.py Dismissed

from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
from datamodel_code_generator.model.pydantic_v2 import UnionMode
from datamodel_code_generator.types import DataTypeManager, StrictTypes

Check notice

Code scanning / CodeQL

Cyclic import Note

Import of module
datamodel_code_generator.types
begins an import cycle.

Copilot Autofix

AI 4 months ago

General approach: Break the cycle by removing or deferring the problematic import while preserving runtime behavior. Since the imported names are only used for type annotations and are not required at runtime, the lowest-risk fix is to avoid importing datamodel_code_generator.types at all in this module and instead annotate those attributes using Any (or a forward reference if we had access to the definitions). This follows the existing pattern in the file where other potentially cyclic types fall back to Any in the non-TYPE_CHECKING branch.

Concrete fix for this file:

  • In the TYPE_CHECKING block (lines 40–47), remove the line from datamodel_code_generator.types import DataTypeManager, StrictTypes.
  • In the corresponding else block (lines 48–56), DataTypeManager and StrictTypes are already defined as Any, so no change is required there.
  • Update type annotations that reference StrictTypes to avoid needing the real type. In this snippet, strict_types: Sequence[StrictTypes] | None = None (line 149) is the only such usage. To eliminate the need for the actual StrictTypes type while maintaining a useful annotation, change this to use Any in the sequence, e.g. Sequence[Any] | None, which is acceptable since Any is already imported at the top of the file.

This change removes the import that forms the cycle, keeps runtime behavior identical, and only slightly weakens type information for one field, which is acceptable in the context of a config model.

Suggested changeset 1
src/datamodel_code_generator/config.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/config.py b/src/datamodel_code_generator/config.py
--- a/src/datamodel_code_generator/config.py
+++ b/src/datamodel_code_generator/config.py
@@ -44,7 +44,6 @@
     from datamodel_code_generator.model import DataModelSet
     from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
     from datamodel_code_generator.model.pydantic_v2 import UnionMode
-    from datamodel_code_generator.types import DataTypeManager, StrictTypes
 else:
     if not is_pydantic_v2():
         Path = Any  # type: ignore[assignment]
@@ -146,7 +145,7 @@
     use_generic_container_types: bool = False
     enable_faux_immutability: bool = False
     disable_appending_item_suffix: bool = False
-    strict_types: Sequence[StrictTypes] | None = None
+    strict_types: Sequence[Any] | None = None
     empty_enum_field_name: str | None = None
     custom_class_name_generator: CallableSchema | None = None
     field_extra_keys: set[str] | None = None
EOF
@@ -44,7 +44,6 @@
from datamodel_code_generator.model import DataModelSet
from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
from datamodel_code_generator.model.pydantic_v2 import UnionMode
from datamodel_code_generator.types import DataTypeManager, StrictTypes
else:
if not is_pydantic_v2():
Path = Any # type: ignore[assignment]
@@ -146,7 +145,7 @@
use_generic_container_types: bool = False
enable_faux_immutability: bool = False
disable_appending_item_suffix: bool = False
strict_types: Sequence[StrictTypes] | None = None
strict_types: Sequence[Any] | None = None
empty_enum_field_name: str | None = None
custom_class_name_generator: CallableSchema | None = None
field_extra_keys: set[str] | None = None
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread src/datamodel_code_generator/config.py Dismissed
Comment thread src/datamodel_code_generator/config.py Dismissed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
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: 4

🧹 Nitpick comments (2)
src/datamodel_code_generator/parser/base.py (1)

71-87: Parser config/parse refactor is coherent and matches the new config models

  • Parser.__init__’s config/options normalization via model_validate(ParserConfig, …) and the mutual-exclusion guard align with how GenerateConfig/ParseConfig are handled elsewhere.
  • Introducing ParseSettings as a lightweight internal carrier for parse-time options simplifies _process_single_module, _generate_module_output, and _generate_empty_init_exports without changing behavior.
  • _prepare_parse_config() still correctly drives use_deferred_annotations, future imports, and optional CodeFormatter.
  • The new imports of DataType/DataTypeManager and their usage in helpers keep types explicit and consistent with the new ParserConfig fields.

I’m deliberately ignoring Ruff’s RUF100 suggestions about # noqa: PLC0415 on the lazy imports, since those directives are intentionally kept for future Ruff configuration changes. Based on learnings, this is expected.

Also applies to: 128-138, 691-825, 2794-2838, 3000-3070, 3072-3195

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

1-214: CLI config TypedDict surface matches the Pydantic schema and enum values

The Literal aliases and CliConfigSchema fields line up with the documented enum values and CliConfigSchema model (paths as strings, set-like options as lists, etc.), giving a useful typed surface for CLI configs. The looser union_mode: Any is acceptable here and avoids pulling in pydantic-specific types into this generated stub; you can tighten it later if you decide to mirror those literals more precisely.

📜 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 23515e6 and 92d41b8.

📒 Files selected for processing (13)
  • pyproject.toml
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/config.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/main/test_main_general.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/datamodel_code_generator/_types/parser_config_dict.py
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
  • pyproject.toml
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/__init__.py
📚 Learning: 2025-12-18T13:35:21.591Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: .coderabbit.yaml:4-6
Timestamp: 2025-12-18T13:35:21.591Z
Learning: CodeRabbit's Ruff tool configuration supports the `config_file` property in `.coderabbit.yaml` to specify the path to the Ruff configuration file (e.g., "pyproject.toml", "ruff.toml", or ".ruff.toml"), as documented at https://docs.coderabbit.ai/tools#configuration-methods.

Applied to files:

  • pyproject.toml
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • pyproject.toml
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
🧬 Code graph analysis (10)
src/datamodel_code_generator/parser/graphql.py (2)
src/datamodel_code_generator/util.py (1)
  • model_validate (261-265)
src/datamodel_code_generator/config.py (3)
  • ParserConfig (601-723)
  • ParserConfigDict (201-313)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/_types/parse_config_dict.py (3)
src/datamodel_code_generator/model/typed_dict.py (1)
  • TypedDict (49-114)
src/datamodel_code_generator/enums.py (3)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • ModuleSplitMode (172-178)
src/datamodel_code_generator/config.py (1)
  • ParseConfig (726-745)
src/datamodel_code_generator/config.py (3)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • GenerateConfig (91-211)
src/datamodel_code_generator/parser/__init__.py (2)
  • DefaultPutDict (28-47)
  • LiteralType (20-25)
src/datamodel_code_generator/__main__.py (1)
  • Config (143-627)
src/datamodel_code_generator/parser/jsonschema.py (4)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (63-173)
src/datamodel_code_generator/config.py (3)
  • ParserConfig (601-723)
  • ParserConfigDict (201-313)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/util.py (2)
  • model_validate (261-265)
  • model_copy (275-279)
src/datamodel_code_generator/format.py (1)
  • DatetimeClassType (50-57)
tests/main/test_main_general.py (6)
src/datamodel_code_generator/config.py (7)
  • GenerateConfig (328-460)
  • ParseConfig (726-745)
  • ParserConfig (601-723)
  • Config (335-339)
  • Config (470-474)
  • Config (608-612)
  • Config (733-737)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (20-27)
src/datamodel_code_generator/parser/graphql.py (1)
  • GraphQLParser (65-507)
src/datamodel_code_generator/parser/jsonschema.py (2)
  • JsonSchemaParser (520-3291)
  • Config (368-373)
src/datamodel_code_generator/__main__.py (1)
  • Config (143-627)
src/datamodel_code_generator/parser/openapi.py (1)
  • OpenAPIParser (165-748)
src/datamodel_code_generator/__init__.py (2)
src/datamodel_code_generator/util.py (3)
  • is_pydantic_v2 (52-57)
  • model_dump (254-258)
  • model_validate (261-265)
src/datamodel_code_generator/http.py (1)
  • get_body (29-45)
src/datamodel_code_generator/_types/generate_config_dict.py (5)
src/datamodel_code_generator/enums.py (5)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • InputFileType (35-45)
src/datamodel_code_generator/_types/cli_config_dict.py (1)
  • DataclassArguments (33-43)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • DataclassArguments (17-27)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (328-460)
src/datamodel_code_generator/parser/openapi.py (4)
src/datamodel_code_generator/parser/base.py (1)
  • parse (3107-3208)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (63-173)
src/datamodel_code_generator/config.py (3)
  • ParserConfig (601-723)
  • ParserConfigDict (201-313)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/model/base.py (1)
  • DataModelFieldBase (151-468)
src/datamodel_code_generator/_types/cli_config_dict.py (2)
src/datamodel_code_generator/enums.py (14)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • StrictTypes (199-206)
  • TargetPydanticVersion (181-189)
src/datamodel_code_generator/config.py (1)
  • CliConfigSchema (463-598)
src/datamodel_code_generator/__main__.py (2)
src/datamodel_code_generator/config.py (6)
  • GenerateConfig (328-460)
  • Config (335-339)
  • Config (470-474)
  • Config (608-612)
  • Config (733-737)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/util.py (2)
  • model_dump (254-258)
  • model_validate (261-265)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/graphql.py

102-102: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/config.py

754-754: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


755-755: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


757-757: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


758-758: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


761-761: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/jsonschema.py

534-534: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/base.py

691-691: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


699-699: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3107-3107: Unused noqa directive (non-enabled: PLR0914)

Remove unused noqa directive

(RUF100)


3114-3114: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3117-3117: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__init__.py

74-74: Unused noqa directive (non-enabled: E402)

Remove unused noqa directive

(RUF100)


466-466: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


483-483: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


507-507: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


613-613: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


902-902: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/openapi.py

181-181: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__main__.py

42-42: Unused noqa directive (non-enabled: TC003)

Remove unused noqa directive

(RUF100)


175-175: Unused noqa directive (non-enabled: N805)

Remove unused noqa directive

(RUF100)


500-500: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


501-501: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


503-503: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


504-504: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


505-505: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


587-587: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


727-727: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


729-729: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


748-748: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


750-750: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


751-751: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1022-1022: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1029-1029: Unused noqa directive (non-enabled: T201)

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). (12)
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.11 on Ubuntu
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (11)
tests/main/test_main_general.py (3)

5-6: New imports for config and parser types look consistent

Bringing in GenerateConfig, ParseConfig, ParserConfig, and the concrete parser classes keeps tests strongly typed against the new config-driven API; no issues here.

Also applies to: 27-32


108-173: Config and CLI validation tests are well targeted

The new tests around Config.extra_template_data, invalid extra_template_data via parse_obj, and malformed aliases/custom formatter kwargs exercise exactly the new validation paths without overreaching; they should catch most regressions in CLI/config coercion logic.


200-325: Good coverage of config vs options contract across generate/Parser/parse

These tests clearly enforce “config XOR individual options” for generate(), Parser.__init__, JsonSchemaParser.parse(), and the GraphQL/OpenAPI/JSONSchema parser constructors, while also confirming that plain mapping configs are accepted and wired through. This gives strong safety net for the new config-driven API.

src/datamodel_code_generator/config.py (2)

76-326: TypedDict and BaseModel config surfaces are coherent and strongly typed

GenerateConfigDict, ParserConfigDict, ParseConfigDict and their corresponding GenerateConfig/ParserConfig/ParseConfig models line up well: field names, enum types, and option shapes are consistent with the rest of the project. Using extra="forbid" on the models is a good choice to catch mis-spelled or unsupported options early.


328-786: Lazy forward-ref rebuild pattern is appropriate; keep PLC0415 noqa markers

_rebuild_config_models() centralizes the heavy imports (Path, ParseResult, DataModel, DataTypeManager, UnionMode) and applies them via model_rebuild/update_forward_refs, which avoids hard import cycles while still giving fully-typed models at runtime. The local imports in this helper, and in callers that re-import config inside methods, justify the # noqa: PLC0415 directives even if RUF100 flags them as unused; they’re a deliberate guard against future linter configuration changes. Based on learnings, this pattern is intentional and should remain.

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

11-27: Generated ParseConfig TypedDict matches runtime model

The TypedDict aliases and ParseConfig keys mirror the ParseConfig BaseModel fields (including enum literals for scope/collision strategy/split mode), which is exactly what downstream tooling and type-checkers need.

pyproject.toml (1)

261-283: Profiles for generating TypedDict config surfaces are well wired

The four [tool.datamodel-codegen.profiles.*] entries correctly reference the new config models and their corresponding _types/*.py outputs, using consistent Ruff-based formatting. This should keep the TypedDict interfaces in sync with the runtime config models with minimal maintenance.

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

79-84: Config-driven JsonSchemaParser.init is sound and cycle-safe

Normalizing configuration via config: ParserConfig | None plus **options: Unpack[ParserConfigDict], rejecting mixed usage, and then defaulting target_datetime_class before calling super().__init__ gives a clear, strongly-typed surface. The lazy import of ParserConfig and _rebuild_config_models() inside __init__ (with # noqa: PLC0415) is appropriate to avoid import cycles while still resolving forward refs at first use. This matches the new tests and overall config design.

Also applies to: 526-549

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

32-34: GraphQL parser config plumbing and use_standard_collections wiring look solid

The new config/options handling, _rebuild_config_models() call, and model_validate(ParserConfig, …) usage are consistent with the base Parser refactor. Deriving self.use_standard_collections from config.use_standard_collections and threading it into _typename_field and parse_field preserves prior behavior while aligning with the centralized config model.

Also applies to: 42-48, 92-118, 192-205, 347-363

src/datamodel_code_generator/__init__.py (1)

60-83: Config-driven generate() pipeline is well-wired and backwards compatible

The new overloads plus the GenerateConfig/GenerateConfigDict + model_validate normalization provide a clean, typed entry point while still supporting legacy keyword options. Input routing, remote_text_cache usage, parser selection, parser/parse-config construction, and defer-formatting behavior all look consistent with previous semantics and the new centralized config models.

Also applies to: 451-515, 519-575, 576-715, 722-781, 783-861

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

27-28: OpenAPI parser’s config-based constructor and datetime defaulting look correct

The new config/options handling for OpenAPIParser.__init__ is consistent with the shared ParserConfig pattern, including _rebuild_config_models() and model_validate(ParserConfig, …). Defaulting target_datetime_class to DatetimeClassType.Awaredatetime when unset keeps the OpenAPI-specific behavior explicit while leaving the generic config model neutral.

Also applies to: 39-40, 170-195

Comment thread src/datamodel_code_generator/__init__.py
Comment on lines +1117 to +1124
extra_template_data: dict[str, dict[str, Any]] | None
if config.extra_template_data is None:
extra_template_data = None
else:
with config.extra_template_data as data:
try:
extra_template_data = json.load(data, object_hook=lambda d: defaultdict(dict, **d))
except json.JSONDecodeError as e:
print(f"Unable to load extra template data: {e}", file=sys.stderr) # noqa: T201
return Exit.ERROR
try:
extra_template_data = defaultdict(dict, **config.extra_template_data)
except (TypeError, ValueError):
return Exit.ERROR
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add error messages for validation failures.

When extra_template_data construction fails, the code returns Exit.ERROR without printing an error message. Users will see an exit code of 2 without understanding what went wrong.

🔎 Proposed fix to add error message
-    try:
-        extra_template_data = defaultdict(dict, **config.extra_template_data)
-    except (TypeError, ValueError):
-        return Exit.ERROR
+    try:
+        extra_template_data = defaultdict(dict, **config.extra_template_data)
+    except (TypeError, ValueError) as e:
+        print(f"Error: Invalid extra_template_data format: {e}", file=sys.stderr)  # noqa: T201
+        return Exit.ERROR
🤖 Prompt for AI Agents
In src/datamodel_code_generator/__main__.py around lines 1117-1124 the code
swallows TypeError/ValueError when building extra_template_data and simply
returns Exit.ERROR; update the except block to print or log a clear error
message to stderr (or the module logger) that includes a short description (e.g.
"Invalid extra_template_data"), the exception message, and the offending
config.extra_template_data value for debugging, and then return Exit.ERROR as
before.

Comment thread src/datamodel_code_generator/__main__.py
Comment thread src/datamodel_code_generator/__main__.py
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: 1

♻️ Duplicate comments (2)
src/datamodel_code_generator/_types/cli_config_dict.py (2)

14-153: Duplicate Enum definitions (same as generate_config_dict.py).

These Enum classes are identical to those in generate_config_dict.py. Refer to the comment on that file regarding extracting these to a shared module.


255-255: Loose typing for union_mode field (same issue as generate_config_dict.py).

Same type safety concern as in generate_config_dict.py line 254. The verification script from that file will also reveal the correct type for this field.

🧹 Nitpick comments (2)
src/datamodel_code_generator/_types/parse_config_dict.py (1)

14-26: Consider consolidating duplicated Enum definitions.

These three Enums (AllExportsCollisionStrategy, AllExportsScope, ModuleSplitMode) are identically defined across multiple _types modules (cli_config_dict.py, generate_config_dict.py, parse_config_dict.py). While this duplication may be intentional in the generation process to avoid cross-dependencies, it creates maintenance overhead and risk of inconsistency.

If the generation architecture allows, consider extracting these shared Enums to a common _types/shared.py module that other _types modules can import from.

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

14-154: Consider extracting duplicate Enum definitions to a shared module.

All 13 Enum classes defined here (lines 14-154) are duplicated identically in cli_config_dict.py. This creates maintenance overhead and potential inconsistencies. Consider extracting these common enums to a shared module (e.g., _types/_common.py or _types/enums.py) and importing them in both files.

📋 Example refactoring approach

Create a new file src/datamodel_code_generator/_types/_common_enums.py:

# Common enums used across generated config TypedDicts
from enum import Enum

class AllExportsCollisionStrategy(Enum):
    error = "error"
    minimal_prefix = "minimal-prefix"
    full_prefix = "full-prefix"

# ... rest of enums

Then update the generation process to import from the shared module instead of regenerating enums in each file.

📜 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 92d41b8 and 4c99478.

📒 Files selected for processing (5)
  • pyproject.toml
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
📚 Learning: 2025-12-18T13:35:21.591Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: .coderabbit.yaml:4-6
Timestamp: 2025-12-18T13:35:21.591Z
Learning: CodeRabbit's Ruff tool configuration supports the `config_file` property in `.coderabbit.yaml` to specify the path to the Ruff configuration file (e.g., "pyproject.toml", "ruff.toml", or ".ruff.toml"), as documented at https://docs.coderabbit.ai/tools#configuration-methods.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
🧬 Code graph analysis (2)
src/datamodel_code_generator/_types/parse_config_dict.py (3)
src/datamodel_code_generator/_types/cli_config_dict.py (3)
  • AllExportsCollisionStrategy (14-17)
  • AllExportsScope (20-22)
  • ModuleSplitMode (101-102)
src/datamodel_code_generator/_types/generate_config_dict.py (3)
  • AllExportsCollisionStrategy (14-17)
  • AllExportsScope (20-22)
  • ModuleSplitMode (105-106)
src/datamodel_code_generator/config.py (1)
  • ParseConfig (726-745)
src/datamodel_code_generator/_types/generate_config_dict.py (3)
src/datamodel_code_generator/_types/parse_config_dict.py (3)
  • AllExportsCollisionStrategy (14-17)
  • AllExportsScope (20-22)
  • ModuleSplitMode (25-26)
src/datamodel_code_generator/_types/parser_config_dict.py (14)
  • AllOfMergeMode (14-17)
  • CollapseRootModelsNameStrategy (20-22)
  • DataclassArguments (25-35)
  • DateClassType (38-41)
  • DatetimeClassType (44-49)
  • FieldTypeCollisionStrategy (52-54)
  • Formatter (57-61)
  • LiteralType (64-67)
  • NamingStrategy (70-74)
  • PythonVersion (77-82)
  • ReadOnlyWriteOnlyModelType (85-87)
  • ReuseScope (90-92)
  • StrictTypes (95-100)
  • TargetPydanticVersion (103-105)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (328-460)
⏰ 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). (11)
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.12 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (3)
src/datamodel_code_generator/_types/parser_config_dict.py (1)

1-218: LGTM! Generated TypedDict definitions are well-formed.

The generated type definitions provide a comprehensive typed configuration surface. All Enum and TypedDict structures are correctly formed, with proper use of NotRequired for optional fields and appropriate type annotations throughout.

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

29-36: LGTM! ParseConfig TypedDict is well-formed.

The TypedDict structure correctly mirrors the ParseConfig model in config.py with proper use of NotRequired for all optional fields.

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

121-121: This file is auto-generated and should not be manually edited.

The ParseResult TypeAlias in cli_config_dict.py is automatically generated by datamodel-code-generator (see file header and pyproject.toml configuration). The loose typing (tuple[Any, Any, Any, Any, Any, Any]) results from how the tool converts urllib.parse.ParseResult (a NamedTuple) to TypedDict format, which cannot directly represent named fields.

If typing improvements are needed, address the source definition in config.py:CliConfigSchema or adjust the generation configuration in pyproject.toml—do not manually edit the generated file, as changes will be overwritten on regeneration.

Comment thread src/datamodel_code_generator/_types/generate_config_dict.py Outdated
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: 2

♻️ Duplicate comments (1)
src/datamodel_code_generator/_types/generate_config_dict.py (1)

144-144: Import UnionMode and regenerate to fix type annotation.

The union_mode field is typed as Any but should be UnionMode | None to match the source GenerateConfig model. The pyproject.toml configuration includes UnionMode in type_overrides (line 264), so adding the import and regenerating should resolve this.

Required import

Add to imports section:

from datamodel_code_generator.model.pydantic_v2 import UnionMode

Then regenerate using the configured profile:

datamodel-codegen --profile generate-config-dict
📜 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 4c99478 and 325d5b6.

📒 Files selected for processing (5)
  • pyproject.toml
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/datamodel_code_generator/_types/parse_config_dict.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
📚 Learning: 2025-12-18T13:35:21.591Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: .coderabbit.yaml:4-6
Timestamp: 2025-12-18T13:35:21.591Z
Learning: CodeRabbit's Ruff tool configuration supports the `config_file` property in `.coderabbit.yaml` to specify the path to the Ruff configuration file (e.g., "pyproject.toml", "ruff.toml", or ".ruff.toml"), as documented at https://docs.coderabbit.ai/tools#configuration-methods.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
🧬 Code graph analysis (3)
src/datamodel_code_generator/_types/generate_config_dict.py (6)
src/datamodel_code_generator/enums.py (15)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • GraphQLScope (155-158)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • TargetPydanticVersion (181-189)
  • StrictTypes (199-206)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/_types/cli_config_dict.py (1)
  • DataclassArguments (32-42)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • DataclassArguments (26-36)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (328-460)
src/datamodel_code_generator/_types/parser_config_dict.py (2)
src/datamodel_code_generator/enums.py (7)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • FieldTypeCollisionStrategy (105-113)
  • NamingStrategy (116-128)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • TargetPydanticVersion (181-189)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/_types/cli_config_dict.py (3)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • DataclassArguments (33-43)
🪛 GitHub Actions: Lint
src/datamodel_code_generator/_types/generate_config_dict.py

[error] 1-1: Ruff formatting check failed. 71 errors fixed by pre-commit hooks.

src/datamodel_code_generator/_types/parser_config_dict.py

[error] 1-1: Ruff formatting check failed. 71 errors fixed by pre-commit hooks.

src/datamodel_code_generator/_types/cli_config_dict.py

[error] 1-1: Ruff formatting check failed. 71 errors fixed by pre-commit hooks.

⏰ 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: 3.11 on macOS
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on Windows
  • 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: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (3)
src/datamodel_code_generator/_types/parser_config_dict.py (1)

1-149: Formatting addressed; structure looks good.

Per the past review comments, the formatting issues reported by the pipeline have been addressed in commits 8c02562 to 92d41b8. The generated TypedDict structure is correct with proper imports and type annotations.

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

1-143: Structure and imports are correct.

The generated TypedDict provides comprehensive configuration typing with proper enum imports and NotRequired fields. Formatting has been addressed per previous commits.

Also applies to: 145-166

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

1-147: Structure and typing surface are comprehensive.

The generated TypedDict provides extensive CLI configuration typing with proper enum references and NotRequired fields. The ParseResult TypeAlias and DataclassArguments definitions are correctly structured. Formatting has been addressed per previous commits.

Also applies to: 149-171

Comment thread pyproject.toml
Comment thread src/datamodel_code_generator/_types/cli_config_dict.py Outdated
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/_types/parser_config_dict.py (1)

28-38: Consider consolidating duplicated DataclassArguments TypedDict.

The DataclassArguments TypedDict is identical to the one in cli_config_dict.py. Since both files are generated, this duplication might be intentional for module independence. However, if the code generator supports it, consider consolidating this into a single shared definition to follow DRY principles and prevent potential inconsistencies.

📜 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 325d5b6 and f985b01.

📒 Files selected for processing (4)
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
📚 Learning: 2025-12-18T13:35:21.591Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: .coderabbit.yaml:4-6
Timestamp: 2025-12-18T13:35:21.591Z
Learning: CodeRabbit's Ruff tool configuration supports the `config_file` property in `.coderabbit.yaml` to specify the path to the Ruff configuration file (e.g., "pyproject.toml", "ruff.toml", or ".ruff.toml"), as documented at https://docs.coderabbit.ai/tools#configuration-methods.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
🧬 Code graph analysis (1)
src/datamodel_code_generator/_types/parser_config_dict.py (4)
src/datamodel_code_generator/enums.py (7)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • FieldTypeCollisionStrategy (105-113)
  • NamingStrategy (116-128)
  • ReadOnlyWriteOnlyModelType (161-169)
  • TargetPydanticVersion (181-189)
  • StrictTypes (199-206)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/_types/cli_config_dict.py (1)
  • DataclassArguments (34-44)
⏰ 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: py312-black22 on Ubuntu
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (2)
src/datamodel_code_generator/_types/parser_config_dict.py (2)

41-151: LGTM: Comprehensive configuration TypedDict.

The ParserConfig TypedDict provides a well-structured, type-safe configuration surface with 110 fields covering all aspects of the parser configuration. The type annotations are correct and align with the enum definitions shown in the codebase.


25-25: No action required. The import of StrictTypes from datamodel_code_generator.types is correct. The types module provides lazy access to StrictTypes (defined in enums.py) via its __getattr__ function for backward compatibility, making the import valid and intentional.

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

♻️ Duplicate comments (1)
src/datamodel_code_generator/__main__.py (1)

175-188: Surface clear error messages for malformed extra_template_data / aliases / custom_formatters_kwargs

Right now, three validation paths fail with a bare Exit.ERROR and no user‑visible message:

  • Building extra_template_data = defaultdict(dict, **config.extra_template_data) when the structure is invalid.
  • aliases not being a dict[str, str].
  • custom_formatters_kwargs not being a dict[str, str].

This leaves users with an unexplained exit code, which has already been flagged in earlier reviews.

You can keep the new typed config flow and still print a concise error to stderr before returning, e.g.:

Example adjustments
    else:
-        try:
-            extra_template_data = defaultdict(dict, **config.extra_template_data)
-        except (TypeError, ValueError):
-            return Exit.ERROR
+        try:
+            extra_template_data = defaultdict(dict, **config.extra_template_data)
+        except (TypeError, ValueError) as e:
+            print(f"Error: invalid extra_template_data: {e}", file=sys.stderr)  # noqa: T201
+            return Exit.ERROR

    if config.aliases is None:
        aliases = None
    else:
        aliases = config.aliases
        if not isinstance(aliases, dict) or not all(
            isinstance(k, str) and isinstance(v, str) for k, v in aliases.items()
        ):
-            return Exit.ERROR
+            print("Error: aliases must be a dict[str, str]", file=sys.stderr)  # noqa: T201
+            return Exit.ERROR

    if config.custom_formatters_kwargs is None:
        custom_formatters_kwargs = None
    else:
        custom_formatters_kwargs = config.custom_formatters_kwargs
        if not isinstance(custom_formatters_kwargs, dict) or not all(
            isinstance(k, str) and isinstance(v, str) for k, v in custom_formatters_kwargs.items()
        ):
-            return Exit.ERROR
+            print(
+                "Error: custom_formatters_kwargs must be a dict[str, str]",
+                file=sys.stderr,
+            )  # noqa: T201
+            return Exit.ERROR

This keeps the behavior the same while making failures debuggable.

Also applies to: 1117-1151

🧹 Nitpick comments (4)
src/datamodel_code_generator/config.py (1)

76-326: De‑duplicate config TypedDict definitions with the _types package to avoid drift

GenerateConfigDict, ParserConfigDict, and ParseConfigDict here mirror the shapes already exposed under datamodel_code_generator._types.*. Maintaining two sets of nearly identical TypedDicts will be easy to desync when fields are added/renamed.

If feasible, consider reusing the _types definitions (e.g., via re-export or a shared stub module) instead of redefining them here, or at least adding a brief comment tying these to the corresponding _types modules so future changes are applied consistently.

src/datamodel_code_generator/__main__.py (2)

567-585: Clarify merge semantics and make the MsgspecStruct special‑case robust to value types

In Config.merge_args:

  • set_args treats any Namespace value that is not None as “set”, which relies on all CLI defaults being None when the user does not pass the option. If any options use store_true/store_false or non‑None defaults, pyproject.toml values will be silently overridden by argparse defaults.
  • The output_model_type special‑case checks set_args.get("output_model_type") == DataModelType.MsgspecStruct.value, which assumes output_model_type is a string. If the parser ever yields a DataModelType enum instance instead, this comparison will never be true and use_annotated won’t be auto‑enabled.

Consider tightening this:

  • Ensure the arg parser uses default=None for options that should not override pyproject values unless explicitly provided, so the value is not None check does what you expect.
  • Make the MsgspecStruct check tolerant of both strings and enums, e.g.:
Proposed tweak
-        if set_args.get("output_model_type") == DataModelType.MsgspecStruct.value:
+        omt = set_args.get("output_model_type")
+        if omt in {DataModelType.MsgspecStruct, DataModelType.MsgspecStruct.value}:
             set_args["use_annotated"] = True

630-641: Be explicit about _extract_additional_imports mutating extra_template_data

_extract_additional_imports() pulls "additional_imports" out of each extra_template_data entry using pop(), and main() then passes the mutated extra_template_data on to generation.

If templates or other code paths were previously relying on extra_template_data[...]["additional_imports"] being present at render time, this will change behavior. If the intent is to normalize those values into config.additional_imports and hide them from templates, it’s worth:

  • Adding a short comment here to document that this helper is intentionally destructive, or
  • Switching to a non‑destructive read (get) and leaving the key in place if you still want templates to see it.

Given how subtle config/template interactions can be, I’d recommend double‑checking existing templates before relying on the destructive behavior.

Also applies to: 1117-1133

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

720-725: Simplify extra_template_data defaulting to avoid redundant defaultdict allocations

In Parser.__init__ you normalize extra_template_data to a defaultdict(dict) and then later do:

self.extra_template_data: defaultdict[str, Any] = extra_template_data or defaultdict(dict)

Because an empty defaultdict is falsy, the or expression always creates a second defaultdict in the “None → new defaultdict” case, discarding the first one.

Functionally this is harmless, but you can simplify and avoid the extra allocation by assigning directly:

Possible simplification
-        if extra_template_data is None:
-            extra_template_data = defaultdict(dict)
-        elif not isinstance(extra_template_data, defaultdict):
-            extra_template_data = defaultdict(dict, extra_template_data)
+        if extra_template_data is None:
+            extra_template_data = defaultdict(dict)
+        elif not isinstance(extra_template_data, defaultdict):
+            extra_template_data = defaultdict(dict, extra_template_data)
...
-        self.extra_template_data: defaultdict[str, Any] = extra_template_data or defaultdict(dict)
+        self.extra_template_data: defaultdict[str, Any] = extra_template_data

This keeps behavior the same while making the intent clearer.

Also applies to: 905-908

📜 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 f985b01 and 9b883b0.

📒 Files selected for processing (4)
  • pyproject.toml
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/parser/base.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/parser/base.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
🧬 Code graph analysis (3)
src/datamodel_code_generator/config.py (4)
src/datamodel_code_generator/enums.py (1)
  • AllExportsCollisionStrategy (92-102)
src/datamodel_code_generator/format.py (2)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)
  • ConfigDict (29-55)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/parser/base.py (3)
src/datamodel_code_generator/types.py (2)
  • DataType (296-780)
  • DataTypeManager (832-910)
src/datamodel_code_generator/config.py (4)
  • ParseConfig (726-745)
  • ParseConfigDict (316-325)
  • ParserConfig (601-723)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (17-24)
src/datamodel_code_generator/__main__.py (5)
src/datamodel_code_generator/config.py (6)
  • GenerateConfig (328-460)
  • Config (335-339)
  • Config (470-474)
  • Config (608-612)
  • Config (733-737)
  • _rebuild_config_models (751-786)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • GenerateConfig (48-168)
src/datamodel_code_generator/util.py (2)
  • model_dump (254-258)
  • model_validate (261-265)
src/datamodel_code_generator/model/pydantic/__init__.py (1)
  • Config (26-47)
src/datamodel_code_generator/__init__.py (4)
  • Error (298-307)
  • generate (452-456)
  • generate (460-463)
  • generate (466-862)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

754-754: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


755-755: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


757-757: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


758-758: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


761-761: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/base.py

691-691: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


699-699: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3107-3107: Unused noqa directive (non-enabled: PLR0914)

Remove unused noqa directive

(RUF100)


3114-3114: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3117-3117: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__main__.py

42-42: Unused noqa directive (non-enabled: TC003)

Remove unused noqa directive

(RUF100)


175-175: Unused noqa directive (non-enabled: N805)

Remove unused noqa directive

(RUF100)


500-500: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


501-501: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


503-503: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


504-504: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


505-505: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


587-587: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


727-727: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


729-729: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


748-748: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


750-750: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


751-751: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1022-1022: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1029-1029: Unused noqa directive (non-enabled: T201)

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). (12)
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: 3.12 on Ubuntu
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (4)
src/datamodel_code_generator/config.py (1)

748-786: Forward‑ref rebuild logic for config models looks correct and idempotent

The _rebuild_config_models() helper cleanly centralizes forward‑ref resolution for all four config models, with:

  • A simple _CONFIG_MODELS_STATE["built"] guard to avoid repeated rebuilds.
  • Lazy, in‑function imports of heavy/cyclic types (Path, DataModel, DataTypeManager, UnionMode) so module import stays cheap and cycles are mitigated.
  • Version‑aware branching between model_rebuild(_types_namespace=...) for Pydantic v2 and update_forward_refs(**types_namespace) for v1.

This matches the project’s existing lazy‑import pattern (including the intentional # noqa: PLC0415 on these imports), and should keep both runtimes aligned without extra work for callers that just need to import GenerateConfig/ParserConfig/ParseConfig/CliConfigSchema.

src/datamodel_code_generator/__main__.py (1)

587-627: Config → GenerateConfig translation looks correct; verify settings_path semantics

Config.to_generate_config() plus run_generate_from_config() nicely centralize the mapping from CLI/pyproject options into a GenerateConfig instance, including:

  • Dropping CLI‑only keys (input, url, check, watch, etc.).
  • Translating use_default / force_optional into the corresponding GenerateConfig flags.
  • Allowing validated dicts for extra_template_data, aliases, and custom_formatters_kwargs.

One point to double‑check: run_generate_from_config always passes settings_path=config.output into to_generate_config, which then feeds GenerateConfig.settings_path. If earlier behavior allowed an explicit “formatter settings path” independent of --output, or used a different default, this might change where CodeFormatter looks for config files.

If that behavior change is intentional, it’d be good to mention it in release notes; if not, consider adding a dedicated CLI/config option for settings_path and wiring that through instead of overloading output.

Also applies to: 940-959

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

72-87: Parser now cleanly accepts either a ParserConfig model or unpacked options

The refactored Parser.__init__ signature:

def __init__(..., *, config: ParserConfig | None = None, **options: Unpack[ParserConfigDict]) -> None:

combined with:

  • The _rebuild_config_models() call before any ParserConfig usage, and
  • The config is not None and options guard, followed by model_validate(ParserConfig, ...)

gives a clear, version‑agnostic way to construct parser instances from either a fully‑typed config object or the old **options style.

This should make the public API easier to evolve while keeping Pydantic v1/v2 compatibility encapsulated in model_validate and _rebuild_config_models.

Also applies to: 691-710


2794-2838: ParseSettings abstraction and config‑driven parse() flow look consistent

The introduction of ParseSettings and its use across:

  • _prepare_parse_config() (computing with_import, use_deferred_annotations, and code_formatter),
  • _process_single_module() (using config.use_deferred_annotations),
  • _generate_module_output() / _generate_empty_init_exports() (driving all_exports_scope/collision behavior and formatting),

plus the new parse() signature that accepts config: ParseConfigModel | None or **options: Unpack[ParseConfigDict] and feeds those into _prepare_parse_config(), gives a coherent, single‑source‑of‑truth configuration for parsing.

The pattern mirrors the ParserConfig handling in __init__ and keeps Pydantic v1/v2 details behind model_validate and _rebuild_config_models, which should make future config evolution more manageable.

Also applies to: 3000-3036, 3072-3105, 3107-3195

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 (3)
src/datamodel_code_generator/_types/cli_config_dict.py (2)

46-46: Consider making ParseResult more specific.

The 6-tuple of Any is very generic. If the tuple positions have known semantic meanings (e.g., url parts, query params), consider documenting them or using a more descriptive TypedDict instead of a tuple.


33-43: DataclassArguments is duplicated across generated files.

This TypedDict appears in both cli_config_dict.py and parser_config_dict.py. While duplication in generated files is acceptable since they're regenerated together, consider whether a shared _types/common.py module would reduce redundancy and make the structure clearer.

pyproject.toml (1)

268-268: Consider multiline formatting for long type_overrides.

The type_overrides dictionaries are very long (150+ characters), making them hard to read and maintain. TOML supports multiline inline tables for better readability.

Example multiline format
type_overrides = {
  AllExportsCollisionStrategy = "datamodel_code_generator.enums.AllExportsCollisionStrategy",
  AllExportsScope = "datamodel_code_generator.enums.AllExportsScope",
  # ... more entries
  UnionMode = "datamodel_code_generator.model.pydantic_v2.UnionMode",
}

Also applies to: 277-277, 295-295

📜 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 9b883b0 and ccca9e6.

📒 Files selected for processing (5)
  • pyproject.toml
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
📚 Learning: 2025-12-18T13:35:21.591Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: .coderabbit.yaml:4-6
Timestamp: 2025-12-18T13:35:21.591Z
Learning: CodeRabbit's Ruff tool configuration supports the `config_file` property in `.coderabbit.yaml` to specify the path to the Ruff configuration file (e.g., "pyproject.toml", "ruff.toml", or ".ruff.toml"), as documented at https://docs.coderabbit.ai/tools#configuration-methods.

Applied to files:

  • src/datamodel_code_generator/_types/parser_config_dict.py
🧬 Code graph analysis (2)
src/datamodel_code_generator/_types/cli_config_dict.py (4)
src/datamodel_code_generator/enums.py (3)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • FieldTypeCollisionStrategy (105-113)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • DataclassArguments (34-44)
src/datamodel_code_generator/_types/parser_config_dict.py (4)
src/datamodel_code_generator/enums.py (8)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • FieldTypeCollisionStrategy (105-113)
  • NamingStrategy (116-128)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • TargetPydanticVersion (181-189)
  • StrictTypes (199-206)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/config.py (1)
  • ParserConfig (601-723)
⏰ 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: Analyze (python)
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.10 on macOS
🔇 Additional comments (4)
src/datamodel_code_generator/_types/parser_config_dict.py (1)

1-149: Generated TypedDict structure is appropriate.

The TypedDict conversion from the Pydantic ParserConfig model appropriately simplifies complex types (Mapping → dict, Sequence → list, custom schema types → str/Any) to standard Python types that TypedDict supports. The Any types for model class references (lines 40-43) are necessary since type objects cannot be precisely represented in TypedDict without complex TYPE_CHECKING imports.

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

28-28: UnionMode import and typing are correct.

The UnionMode type is properly imported (line 28) and used (line 149), resolving the previously flagged typing issue.

Also applies to: 149-149

pyproject.toml (2)

246-250: Coverage exclusion for generated files is appropriate.

Excluding src/datamodel_code_generator/_types/* from coverage is correct since these are generated TypedDict files that don't require test coverage.


265-299: Profile configurations are well-structured and consistent.

The four datamodel-codegen profiles are properly configured with appropriate type overrides, formatters, and output paths. The UnionMode type override is correctly included in the relevant profiles (generate-config-dict, parser-config-dict, cli-config-dict).

Comment thread src/datamodel_code_generator/parser/base.py Dismissed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Fixed
Comment thread src/datamodel_code_generator/parser/base.py Dismissed
Comment thread src/datamodel_code_generator/_types/generate_config_dict.py Fixed
Comment thread src/datamodel_code_generator/_types/parser_config_dict.py Fixed
Comment thread src/datamodel_code_generator/config.py Dismissed
Comment thread src/datamodel_code_generator/config.py Dismissed
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

♻️ Duplicate comments (2)
src/datamodel_code_generator/config.py (1)

507-542: Lazy forward-ref rebuilding and # noqa: PLC0415 are appropriate here

The _rebuild_config_models() helper correctly centralizes the forward-ref resolution for all four config models using _types_namespace and switches between model_rebuild (v2) and update_forward_refs (v1). The local imports guarded by # noqa: PLC0415 are intentionally lazy to break cycles with model.base and types, and per prior project learnings those PLC0415 markers should be kept even though Ruff’s RUF100 flags them as “unused” today.

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

1736-1783: Lazy DataType import + PLC0415 noqa should be retained

The on-demand from datamodel_code_generator.types import DataType # noqa: PLC0415 inside __collapse_root_models avoids a heavy import (and potential cycles) for callers that don’t use collapse_root_models. Keeping the PLC0415 noqa here matches the project convention of explicitly allowing lazy imports, even if Ruff’s RUF100 currently reports it as “unused”.

🧹 Nitpick comments (2)
src/datamodel_code_generator/parser/base.py (1)

691-827: Config-driven Parser.init is sound; note breaking “config + options” combination

The refactored Parser.__init__ correctly:

  • Enforces mutual exclusivity between config and **options with a clear ValueError.
  • Validates both dict-style options and pre-built objects via model_validate(parser_config_model, …).
  • Normalizes extra_template_data to a defaultdict(dict) and wires all ParserConfig fields onto instance attributes with unchanged semantics.

This is a behaviour change for callers that previously mixed explicit kwargs with a config-like object; worth documenting, but the implementation itself looks solid.

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

36-169: Generated GenerateConfig TypedDict matches the Pydantic model and JSON-friendly containers

DataclassArguments and GenerateConfig here mirror the fields and high-level types of GenerateConfig in config.py, while appropriately using JSON/CLI-friendly containers (list/dict instead of Sequence/Mapping/set) and optional Path/enum types under TYPE_CHECKING. Given this file is generated, the current shape looks correct; any future tweaks should come from updating the generator/schema rather than hand-editing the TypedDict.

📜 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 29bca8a and 8455346.

📒 Files selected for processing (6)
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/parser/base.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/parser/base.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/generate_config_dict.py
🧬 Code graph analysis (3)
src/datamodel_code_generator/config.py (3)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
  • DataclassArguments (36-46)
  • GenerateConfig (49-169)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (17-24)
src/datamodel_code_generator/_types/generate_config_dict.py (4)
src/datamodel_code_generator/enums.py (16)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • AllOfMergeMode (142-152)
  • CollapseRootModelsNameStrategy (131-139)
  • DataModelType (48-56)
  • FieldTypeCollisionStrategy (105-113)
  • GraphQLScope (155-158)
  • InputFileType (35-45)
  • ModuleSplitMode (172-178)
  • NamingStrategy (116-128)
  • OpenAPIScope (70-78)
  • ReadOnlyWriteOnlyModelType (161-169)
  • ReuseScope (59-67)
  • TargetPydanticVersion (181-189)
  • UnionMode (192-196)
  • StrictTypes (199-206)
src/datamodel_code_generator/format.py (4)
  • DateClassType (60-65)
  • DatetimeClassType (50-57)
  • Formatter (171-177)
  • PythonVersion (68-140)
src/datamodel_code_generator/parser/__init__.py (1)
  • LiteralType (20-25)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (84-216)
src/datamodel_code_generator/parser/base.py (3)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (17-24)
src/datamodel_code_generator/config.py (3)
  • ParseConfig (482-501)
  • ParserConfig (357-479)
  • _rebuild_config_models (507-542)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (41-151)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

510-510: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


511-511: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


513-513: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


514-514: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


517-517: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/parser/base.py

691-691: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


699-699: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


702-702: Unused noqa directive (non-enabled: SLF001)

Remove unused noqa directive

(RUF100)


1736-1736: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3112-3112: Unused noqa directive (non-enabled: PLR0914)

Remove unused noqa directive

(RUF100)


3119-3119: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


3122-3122: Unused noqa directive (non-enabled: SLF001)

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

84-217: Unified GenerateConfig model looks consistent with existing options

The GenerateConfig BaseModel mirrors the existing generator options well (types/defaults align with the new TypedDict surface and existing CLI flags), and extra="forbid"/arbitrary_types_allowed=True is an appropriate balance here. I don’t see behavioural regressions in how generator options are modeled.


219-355: CliConfigSchema separation keeps CLI schema concerns isolated

Defining CliConfigSchema as a separate BaseModel (rather than reusing GenerateConfig) is a sensible split between “CLI surface” and “generator core” while still sharing enum/types. The config, defaults, and stricter extra="forbid" settings look appropriate for validating CLI-derived config.


357-502: ParserConfig / ParseConfig shapes match parser usage

ParserConfig and ParseConfig line up with how Parser.__init__() and Parser.parse() consume configuration (data_model types, re-use controls, exports settings, split mode, etc.), and using the same v1/v2 pattern (model_config vs nested Config) keeps compatibility tidy. This should make the new config-driven entry points predictable and type-safe.

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

71-87: TYPE_CHECKING imports and util helpers align with new config models

The added model_copy, model_dump, and model_validate imports plus TYPE_CHECKING-only aliases (ParseConfigModel, ParseConfigDict, ParserConfig, ParserConfigDict, DataType, DataTypeManager, Unpack) correctly describe the new config-driven surface without affecting runtime import order. This keeps type-checkers happy while deferring actual config module loading to the lazy imports further down.


128-137: ParseSettings NamedTuple cleanly encapsulates parse-time options

ParseSettings captures just the knobs actually needed during module/code-generation (with_import, deferred annotations, formatter, exports scope/collision strategy, split mode). Using this small immutable object simplifies passing settings through _process_single_module, _generate_module_output, and _generate_empty_init_exports without further bloating method signatures.


2799-2843: _prepare_parse_config → ParseSettings wiring preserves previous semantics

_prepare_parse_config now returns ParseSettings, computing:

  • use_deferred_annotations using the same combination of Python version, with_import, and disable_future_imports.
  • Optional CodeFormatter only when format_ is truthy.
  • A normalized boolean with_import=bool(with_import) for downstream checks.

This keeps the old behaviour while making the parser pipeline consume a single settings object instead of a pile of discrete parameters.


2917-2975: Propagating ParseSettings into _process_single_module is a good encapsulation

Plumbing config: ParseSettings into _process_single_module and using config.use_deferred_annotations for sorting ensures module-level processing has just the knobs it needs without re-reading top-level Parser attributes. The rest of the method remains behaviourally identical.


3005-3111: _generate_module_output / _generate_empty_init_exports correctly consult ParseSettings

Both _generate_module_output and _generate_empty_init_exports now:

  • Use config.all_exports_scope / config.all_exports_collision_strategy instead of separate parameters.
  • Respect config.with_import when deciding whether to emit imports.
  • Run config.code_formatter if present.

That keeps all exports and formatting behaviour governed strictly by the config models, matching the new ParseSettings design.


3112-3198: parse() now mirrors init’s config/kwargs contract and centralizes validation

The new parse() implementation:

  • Lazily imports the config module and calls _rebuild_config_models() to ensure forward refs are ready.
  • Enforces the same “either config or **options, not both” rule as __init__.
  • Uses model_validate(parse_config_model, …) for both dict and object inputs, then passes the resulting values into _prepare_parse_config.
  • Relies on the resulting parse_settings throughout the rest of the pipeline (module structure, generation, empty-init exports).

This gives a consistent, strongly-typed story for parse-time configuration without altering the actual parsing/generation algorithm.

Comment thread src/datamodel_code_generator/_types/generate_config_dict.py Fixed
Comment thread src/datamodel_code_generator/_types/parser_config_dict.py Fixed
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/__init__.py (1)

892-927: Consider adding *Dict variants to __all__ for consistency.

The __getattr__ function exposes GenerateConfigDict, ParserConfigDict, and ParseConfigDict, but these are not listed in __all__. This means:

  • Direct imports work: from datamodel_code_generator import GenerateConfigDict
  • Star imports won't include them: from datamodel_code_generator import *

If these are intended as public API, consider adding them to __all__:

"GenerateConfigDict",
"ParserConfigDict", 
"ParseConfigDict",
📜 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 a7db803 and 362a12b.

📒 Files selected for processing (6)
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
  • src/datamodel_code_generator/_types/parse_config_dict.py
  • src/datamodel_code_generator/_types/parser_config_dict.py
  • src/datamodel_code_generator/config.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/datamodel_code_generator/_types/parser_config_dict.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/__init__.py
📚 Learning: 2025-12-18T13:43:16.235Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2681
File: tests/cli_doc/test_cli_doc_coverage.py:82-82
Timestamp: 2025-12-18T13:43:16.235Z
Learning: In datamodel-code-generator project, Ruff preview mode is enabled via `lint.preview = true` in pyproject.toml. This enables preview rules like PLR6301 (no-self-use), so `noqa: PLR6301` directives are necessary and should not be removed even if RUF100 suggests they are unused.

Applied to files:

  • src/datamodel_code_generator/_types/cli_config_dict.py
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/_types/generate_config_dict.py
🧬 Code graph analysis (5)
src/datamodel_code_generator/_types/parse_config_dict.py (2)
src/datamodel_code_generator/enums.py (3)
  • AllExportsCollisionStrategy (92-102)
  • AllExportsScope (81-89)
  • ModuleSplitMode (172-178)
src/datamodel_code_generator/config.py (1)
  • ParseConfig (545-578)
src/datamodel_code_generator/config.py (6)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
  • DataclassArguments (34-44)
  • GenerateConfig (47-167)
src/datamodel_code_generator/_types/parser_config_dict.py (2)
  • DataclassArguments (26-36)
  • ParserConfig (39-149)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/model/__init__.py (1)
  • DataModelSet (25-35)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (15-22)
src/datamodel_code_generator/__main__.py (1)
  • Config (143-627)
src/datamodel_code_generator/_types/cli_config_dict.py (3)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • DataclassArguments (34-44)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • DataclassArguments (26-36)
src/datamodel_code_generator/config.py (1)
  • CliConfigSchema (220-355)
src/datamodel_code_generator/__init__.py (5)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • GenerateConfig (47-167)
src/datamodel_code_generator/config.py (6)
  • GenerateConfig (85-217)
  • ParseConfig (545-578)
  • ParserConfig (358-542)
  • _rebuild_config_models (584-619)
  • _from_generate_config (483-542)
  • _from_generate_config (567-578)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (15-22)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (39-149)
src/datamodel_code_generator/format.py (3)
  • Formatter (171-177)
  • CodeFormatter (183-421)
  • format_directory (406-421)
src/datamodel_code_generator/_types/generate_config_dict.py (3)
src/datamodel_code_generator/_types/cli_config_dict.py (1)
  • DataclassArguments (33-43)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • DataclassArguments (26-36)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (85-217)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

492-492: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


587-587: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


588-588: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


590-590: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


591-591: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


594-594: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__init__.py

74-74: Unused noqa directive (non-enabled: E402)

Remove unused noqa directive

(RUF100)


468-468: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)

Remove unused noqa directive

(RUF100)


485-485: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


510-510: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


616-616: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


688-688: Unused noqa directive (non-enabled: SLF001)

Remove unused noqa directive

(RUF100)


702-702: Unused noqa directive (non-enabled: SLF001)

Remove unused noqa directive

(RUF100)


873-873: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


877-877: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


882-882: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


884-884: Unused noqa directive (non-enabled: PLC0415)

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). (13)
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on macOS
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (10)
src/datamodel_code_generator/_types/generate_config_dict.py (1)

1-167: Generated TypedDict structure looks correct.

The DataclassArguments and GenerateConfig TypedDicts are well-structured and align with the corresponding Pydantic models in config.py. The field types appropriately use NotRequired for optional fields and reference the correct enum types.

Note: The cyclic import from datamodel_code_generator.types (line 31) was previously flagged by static analysis. This appears to be an accepted pattern in this codebase for generated type stubs.

src/datamodel_code_generator/_types/cli_config_dict.py (2)

46-46: ParseResult TypeAlias simplification is appropriate for serialization.

The tuple[Any, Any, Any, Any, Any, Any] representation of ParseResult is a reasonable simplification for JSON/CLI serialization contexts. The actual urllib.parse.ParseResult is a named tuple with 6 elements, so this preserves the structure while avoiding complex type dependencies in the generated TypedDict.


49-172: CliConfigSchema TypedDict is comprehensive and well-aligned.

The TypedDict correctly mirrors the CliConfigSchema Pydantic model in config.py, including CLI-specific fields (check, debug, disable_warnings, watch, watch_delay, url) that differentiate it from GenerateConfig.

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

1-22: ParseConfig TypedDict is correctly defined.

The generated TypedDict is minimal and focused, containing only the parse-time configuration fields. It correctly aligns with the ParseConfig Pydantic model in config.py.

src/datamodel_code_generator/config.py (3)

48-56: Runtime type fallbacks for Pydantic v1 compatibility.

The pattern of setting types to Any for Pydantic v1 runtime is appropriate. Note that UnionMode is unconditionally set to Any (line 56) outside the is_pydantic_v2() check, which is intentional since UnionMode is only available in the pydantic_v2 module and may not be importable at all in some environments.


482-542: ParserConfig._from_generate_config conversion logic is sound.

The method correctly:

  1. Builds effective dataclass_arguments from frozen_dataclasses and keyword_only flags
  2. Sets enum_field_as_literal to LiteralType.All for TypingTypedDict output
  3. Forces set_default_enum_member to True for DataclassesDataclass output
  4. Computes defer_formatting based on output path having no suffix
  5. Uses field intersection to safely copy overlapping config values

584-619: Forward reference rebuilding is correctly implemented.

The _rebuild_config_models() function properly handles:

  1. Singleton pattern via _CONFIG_MODELS_STATE to avoid redundant rebuilds
  2. Lazy imports of runtime types to break cyclic dependencies
  3. UnionMode import wrapped in try/except for environments without pydantic_v2
  4. Both Pydantic v1 (update_forward_refs) and v2 (model_rebuild) paths

Regarding the static analysis hints about unused # noqa: PLC0415 directives: Based on learnings, these defensive directives should be kept to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

src/datamodel_code_generator/__init__.py (3)

451-473: Function overloads provide good type safety for the dual API.

The overload pattern correctly distinguishes between:

  1. generate(input_, config=config) - using a GenerateConfig object
  2. generate(input_, **options) - using unpacked GenerateConfigDict kwargs

The implementation at lines 494-500 properly validates mutual exclusivity between config and options.


688-704: Config-driven parser construction is clean and correct.

The refactored flow:

  1. Creates ParserConfig via _from_generate_config() with computed values
  2. Instantiates the parser with config=parser_config
  3. Creates ParseConfig via _from_generate_config()
  4. Calls parser.parse(config=parse_config)

This centralizes configuration handling and ensures consistent parameter passing.


880-886: UnionMode fallback logic is correct and intentional.

The implementation properly handles the pydantic v2 UnionMode feature with appropriate fallback. When UnionMode cannot be imported from pydantic_v2, the code falls back to config.UnionMode, which is defined as Any in non-pydantic-v2 environments (config.py line 56). This pattern mirrors the try/except logic in config.py itself and is the expected behavior since UnionMode is a pydantic v2-specific feature. No changes needed.

all_exports_collision_strategy=all_exports_collision_strategy,
module_split_mode=module_split_mode,
if input_file_type == InputFileType.OpenAPI:
parser = OpenAPIParser(

Check failure

Code scanning / CodeQL

Potentially uninitialized local variable Error

Local variable 'OpenAPIParser' may be used before it is initialized.

Copilot Autofix

AI 4 months ago

In general, to fix a “potentially uninitialized local variable” involving a class or function name in Python, ensure that the name is bound before use, and that it is bound in a way consistent with how it is being used (global vs. local). For parser classes like OpenAPIParser, GraphQLParser, and JsonSchemaParser, the intended scope is module-global: they should be imported from their respective modules at the top of __init__.py, not assigned inside the generate function.

The single best fix here, without changing behavior, is to add explicit imports for the parser classes at the module level along with the other imports. This makes them unambiguous global names and avoids any possibility that Python will treat them as locals or that they will be referenced before binding. We do not touch the logic that chooses which parser to instantiate; we only ensure that the classes are defined. Concretely, in src/datamodel_code_generator/__init__.py, in the imports area near the existing from datamodel_code_generator.parser import DefaultPutDict, LiteralType, we add imports for OpenAPIParser, GraphQLParser, and JsonSchemaParser from their respective modules under datamodel_code_generator.parser. No additional helper methods or external libraries are needed.

Suggested changeset 1
src/datamodel_code_generator/__init__.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/__init__.py b/src/datamodel_code_generator/__init__.py
--- a/src/datamodel_code_generator/__init__.py
+++ b/src/datamodel_code_generator/__init__.py
@@ -56,6 +56,9 @@
     PythonVersionMin,
 )
 from datamodel_code_generator.parser import DefaultPutDict, LiteralType
+from datamodel_code_generator.parser.graphql import GraphQLParser
+from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
+from datamodel_code_generator.parser.openapi import OpenAPIParser
 
 if TYPE_CHECKING:
     from typing_extensions import Unpack
EOF
@@ -56,6 +56,9 @@
PythonVersionMin,
)
from datamodel_code_generator.parser import DefaultPutDict, LiteralType
from datamodel_code_generator.parser.graphql import GraphQLParser
from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
from datamodel_code_generator.parser.openapi import OpenAPIParser

if TYPE_CHECKING:
from typing_extensions import Unpack
Copilot is powered by AI and may make mistakes. Always verify output.
use_status_code_in_response_name=config.use_status_code_in_response_name,
)
elif input_file_type == InputFileType.GraphQL:
parser = GraphQLParser(

Check failure

Code scanning / CodeQL

Potentially uninitialized local variable Error

Local variable 'GraphQLParser' may be used before it is initialized.

Copilot Autofix

AI 4 months ago

Generally, this kind of issue is fixed by ensuring the variable/name is definitely bound before any possible use. For a class like GraphQLParser, that means adding an unconditional import at the module level (not inside if TYPE_CHECKING:) so that the name is always available when generate() runs and the GraphQL branch is taken.

The best fix here, without changing behavior, is to add a regular import for GraphQLParser alongside the other parser-related imports at the top of src/datamodel_code_generator/__init__.py. Since we are only allowed to edit shown snippets, we will add a new import line in the visible import section near the existing from datamodel_code_generator.parser import DefaultPutDict, LiteralType. A reasonable and conventional path is from datamodel_code_generator.parser.graphql import GraphQLParser, which introduces the missing symbol without touching the rest of the logic. No other code changes are needed: the elif input_file_type == InputFileType.GraphQL: block will then always see a properly initialized GraphQLParser name.

Concretely:

  • Edit src/datamodel_code_generator/__init__.py in the import section around lines 58–59.
  • Add an explicit import statement for GraphQLParser from its likely submodule.
  • Do not change existing imports or the parser construction logic around lines 683–702.
Suggested changeset 1
src/datamodel_code_generator/__init__.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/__init__.py b/src/datamodel_code_generator/__init__.py
--- a/src/datamodel_code_generator/__init__.py
+++ b/src/datamodel_code_generator/__init__.py
@@ -56,6 +56,7 @@
     PythonVersionMin,
 )
 from datamodel_code_generator.parser import DefaultPutDict, LiteralType
+from datamodel_code_generator.parser.graphql import GraphQLParser
 
 if TYPE_CHECKING:
     from typing_extensions import Unpack
EOF
@@ -56,6 +56,7 @@
PythonVersionMin,
)
from datamodel_code_generator.parser import DefaultPutDict, LiteralType
from datamodel_code_generator.parser.graphql import GraphQLParser

if TYPE_CHECKING:
from typing_extensions import Unpack
Copilot is powered by AI and may make mistakes. Always verify output.
data_model_union_type=data_model_types.union_model,
)
else:
parser = JsonSchemaParser(

Check failure

Code scanning / CodeQL

Potentially uninitialized local variable Error

Local variable 'JsonSchemaParser' may be used before it is initialized.

Copilot Autofix

AI 4 months ago

In general, this kind of issue is fixed by ensuring that any variable or name used in a function is definitely bound before it is referenced. For parser classes like JsonSchemaParser, the right approach is to import them at module scope so they are always available when the generate-like function executes, rather than relying on conditional or implicit definitions.

Concretely, in src/datamodel_code_generator/__init__.py, we should add explicit imports for OpenAPIParser, GraphQLParser, and JsonSchemaParser from their respective modules at the top of the file, alongside the other datamodel_code_generator imports. This guarantees that JsonSchemaParser (and the other parsers) are defined in the module’s global scope before any call to this function, eliminating the possibility of an uninitialized local variable. No changes are required to the logic around the if/elif/else that selects the parser; only the imports need to be added.

Assuming the standard layout of this project, these classes live under datamodel_code_generator.parser.openapi, .graphql, and .jsonschema. We therefore add:

  • from datamodel_code_generator.parser.openapi import OpenAPIParser
  • from datamodel_code_generator.parser.graphql import GraphQLParser
  • from datamodel_code_generator.parser.jsonschema import JsonSchemaParser

near the other import statements at the top of the file. No additional helper methods or definitions are needed.

Suggested changeset 1
src/datamodel_code_generator/__init__.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/datamodel_code_generator/__init__.py b/src/datamodel_code_generator/__init__.py
--- a/src/datamodel_code_generator/__init__.py
+++ b/src/datamodel_code_generator/__init__.py
@@ -56,6 +56,9 @@
     PythonVersionMin,
 )
 from datamodel_code_generator.parser import DefaultPutDict, LiteralType
+from datamodel_code_generator.parser.graphql import GraphQLParser
+from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
+from datamodel_code_generator.parser.openapi import OpenAPIParser
 
 if TYPE_CHECKING:
     from typing_extensions import Unpack
EOF
@@ -56,6 +56,9 @@
PythonVersionMin,
)
from datamodel_code_generator.parser import DefaultPutDict, LiteralType
from datamodel_code_generator.parser.graphql import GraphQLParser
from datamodel_code_generator.parser.jsonschema import JsonSchemaParser
from datamodel_code_generator.parser.openapi import OpenAPIParser

if TYPE_CHECKING:
from typing_extensions import Unpack
Copilot is powered by AI and may make mistakes. Always verify output.
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

♻️ Duplicate comments (1)
src/datamodel_code_generator/config.py (1)

76-82: Verify cyclic imports with _types modules are acceptable.

CodeQL flagged cyclic imports involving the _types submodules (lines 76-78). While the TYPE_CHECKING guards (lines 40-56) help with type-checking time, these module-level runtime imports may create actual circular dependencies if the _types modules import back from config.py.

Run the following to confirm the import order and dependencies:

#!/bin/bash
# Check if _types modules import from config
echo "=== Checking _types/generate_config_dict.py ==="
rg -n "from.*config import" src/datamodel_code_generator/_types/generate_config_dict.py || echo "No imports from config"

echo -e "\n=== Checking _types/parse_config_dict.py ==="
rg -n "from.*config import" src/datamodel_code_generator/_types/parse_config_dict.py || echo "No imports from config"

echo -e "\n=== Checking _types/parser_config_dict.py ==="
rg -n "from.*config import" src/datamodel_code_generator/_types/parser_config_dict.py || echo "No imports from config"

echo -e "\n=== Checking import structure ==="
python -c "import sys; sys.path.insert(0, 'src'); import datamodel_code_generator.config" 2>&1 | head -20
🧹 Nitpick comments (1)
src/datamodel_code_generator/config.py (1)

220-356: Consider reducing duplication with GenerateConfig.

CliConfigSchema duplicates most of GenerateConfig with a few additions (CLI-specific fields like check, debug, watch). While this works, consider whether inheritance or composition could reduce maintenance burden.

Potential refactor approach

You could define a shared base class or use composition:

class SharedConfigFields(BaseModel):
    # Common fields here
    ...

class GenerateConfig(SharedConfigFields):
    # Generate-specific fields
    ...

class CliConfigSchema(SharedConfigFields):
    # CLI-specific fields
    input: Path | str | None = None
    check: bool = False
    ...

This would make it easier to maintain consistency and avoid field drift between the two models.

📜 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 c6a5679 and ffb9e4a.

📒 Files selected for processing (2)
  • src/datamodel_code_generator/config.py
  • tests/test_public_api_signature.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
🧬 Code graph analysis (1)
tests/test_public_api_signature.py (1)
src/datamodel_code_generator/parser/base.py (1)
  • Parser (684-3107)
🪛 GitHub Actions: Lint
tests/test_public_api_signature.py

[error] 9-9: ruff formatting failed: 1 error fixed, 0 remaining. The hook modified the file (docstring content) to conform to style.

🪛 GitHub Check: CodeQL
src/datamodel_code_generator/config.py

[notice] 47-47: Cyclic import
Import of module datamodel_code_generator.types begins an import cycle.

🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

358-358: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


369-369: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


612-612: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


613-613: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


615-615: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


616-616: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


619-619: Unused noqa directive (non-enabled: PLC0415)

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). (8)
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: Analyze (python)
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: benchmarks
🔇 Additional comments (7)
tests/test_public_api_signature.py (2)

11-39: LGTM! Comprehensive public API signature validation.

The tests effectively validate backward compatibility by checking:

  • Parameter presence and ordering
  • Keyword-only constraint on config parameter
  • Default value of None for config
  • Presence of **options for backward compatibility
  • TypedDict runtime availability

1-9: Pipeline formatting issue auto-corrected.

The ruff formatter modified this section to conform to style. Ensure the auto-formatted changes are committed.

⛔ Skipped due to learnings
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.
src/datamodel_code_generator/config.py (5)

85-218: LGTM! Well-structured configuration model.

The GenerateConfig model comprehensively covers all generation options with:

  • Proper Pydantic v1/v2 compatibility handling
  • Clear field definitions with appropriate defaults
  • Good type annotations throughout

358-388: LGTM! Helper function correctly assembles parser configuration.

The function effectively consolidates parser config overrides from various sources. The lazy import on line 369 with its defensive # noqa: PLC0415 aligns with the project's practice of keeping such directives for future-proofing.

Based on learnings, defensive # noqa: PLC0415 directives should be retained.


390-568: LGTM! ParserConfig construction and transformation logic is sound.

The _from_generate_config classmethod correctly:

  • Derives effective configuration values based on model type
  • Handles Pydantic v1/v2 field access differences
  • Filters fields to common subset before merging overrides
  • Validates the final configuration

570-604: LGTM! ParseConfig follows consistent pattern.

The model and its _from_generate_config method follow the same sound approach as ParserConfig, maintaining consistency across the config transformation API.


609-644: LGTM! Forward reference resolution correctly handles v1/v2 differences.

The function properly:

  • Guards against multiple rebuilds with state tracking
  • Uses lazy imports to defer loading (with defensive noqa directives per project convention)
  • Builds appropriate types namespace for both Pydantic versions
  • Handles ImportError for Pydantic v2-only types

The CodeQL warnings about cyclic imports on lines 615-616 are mitigated by placing these imports inside the function, breaking the cycle at module initialization time.

Based on learnings, the defensive # noqa: PLC0415 directives should be retained.

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

♻️ Duplicate comments (1)
src/datamodel_code_generator/config.py (1)

607-645: _rebuild_config_models safely resolves forward refs and UnionMode

The rebuild function:

  • Short-circuits after the first call via _CONFIG_MODELS_STATE.
  • Lazily imports Path/ParseResult/DataModel/DataTypeManager/etc. with # noqa: PLC0415 to keep lazy imports explicit (consistent with project learnings).
  • Handles missing UnionMode gracefully by falling back to Any.
  • Calls model_rebuild (v2) or update_forward_refs (v1) on all four config models.

This should address the cyclic-import concerns raised by previous scanners. I would keep the # noqa: PLC0415 comments here, in line with your existing pattern.

Based on learnings, the Ruff RUF100 warnings for these # noqa: PLC0415 markers can be ignored; they are intentional for future-proofing lazy imports.

🧹 Nitpick comments (2)
src/datamodel_code_generator/config.py (1)

358-387: _build_parser_config_overrides: behavior looks correct, minor nit on noqa

The helper:

  • Derives base_path only when input_ is a Path pointing to a file.
  • Wires in all data_model_types components.
  • Propagates default_field_extras and effective enum/dataclass settings.
  • Uses defer_formatting when output is a directory-like path (suffix empty).

All of that matches the parser pipeline. The # noqa: PLR0913 is currently reported as unused by Ruff in the static hints; if PLR0913 isn’t enabled in your config anymore, you can safely drop that directive.

Please confirm against your current Ruff config whether PLR0913 is enabled; if not, removing the # noqa will clear the RUF100 warning.

src/datamodel_code_generator/__main__.py (1)

587-627: to_generate_config centralizes CLI → GenerateConfig translation

The helper:

  • Dumps self to a dict.
  • Drops CLI-only keys and fields that shouldn’t reach GenerateConfig.
  • Maps use_default/force_optional onto apply_default_values_for_required_fields and force_optional_for_required_fields.
  • Overwrites extra_template_data, aliases, custom_formatters_kwargs, output, command_line, and settings_path with already-validated values.
  • Returns a GenerateConfig via model_validate.

This is the right abstraction point and matches the tests’ expectations. Only tiny nit: the # noqa: PLR0913 on the signature may be unnecessary if that rule isn’t enabled, but it’s harmless.

📜 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 ffb9e4a and 6ae0294.

📒 Files selected for processing (6)
  • pyproject.toml
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/config.py
  • tests/main/test_main_general.py
  • tests/main/test_public_api_direct.py
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-25T09:22:14.661Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/model/pydantic/__init__.py:43-43
Timestamp: 2025-12-25T09:22:14.661Z
Learning: In datamodel-code-generator project, defensive `# noqa: PLC0415` directives should be kept on lazy imports (imports inside functions/methods) even when Ruff reports them as unused via RUF100, to prepare for potential future Ruff configuration changes that might enable the import-outside-top-level rule.

Applied to files:

  • src/datamodel_code_generator/config.py
📚 Learning: 2025-12-25T09:22:57.664Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:22:57.664Z
Learning: In datamodel-code-generator, the is_pydantic_v2() and is_pydantic_v2_11() functions in src/datamodel_code_generator/util.py intentionally use global variable caching (_is_v2, _is_v2_11) on top of lru_cache for performance optimization. This dual-layer caching eliminates function call overhead and cache lookup overhead for frequently-called version checks. The PLW0603 linter warnings should be suppressed with # noqa: PLW0603 as this is a deliberate design choice.

Applied to files:

  • src/datamodel_code_generator/config.py
🧬 Code graph analysis (4)
tests/main/test_main_general.py (3)
src/datamodel_code_generator/config.py (7)
  • GenerateConfig (85-217)
  • ParseConfig (571-604)
  • ParserConfig (390-568)
  • Config (92-96)
  • Config (227-231)
  • Config (397-401)
  • Config (578-582)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
  • GenerateConfig (49-169)
src/datamodel_code_generator/_types/parser_config_dict.py (1)
  • ParserConfig (41-151)
src/datamodel_code_generator/config.py (6)
src/datamodel_code_generator/_types/cli_config_dict.py (2)
  • DataclassArguments (35-45)
  • CliConfigSchema (51-174)
src/datamodel_code_generator/_types/generate_config_dict.py (2)
  • DataclassArguments (36-46)
  • GenerateConfig (49-169)
src/datamodel_code_generator/parser/__init__.py (2)
  • DefaultPutDict (28-47)
  • LiteralType (20-25)
src/datamodel_code_generator/util.py (1)
  • is_pydantic_v2 (52-57)
src/datamodel_code_generator/model/__init__.py (1)
  • DataModelSet (25-35)
src/datamodel_code_generator/_types/parse_config_dict.py (1)
  • ParseConfig (17-24)
src/datamodel_code_generator/__main__.py (2)
src/datamodel_code_generator/config.py (6)
  • GenerateConfig (85-217)
  • Config (92-96)
  • Config (227-231)
  • Config (397-401)
  • Config (578-582)
  • _rebuild_config_models (610-645)
src/datamodel_code_generator/util.py (2)
  • model_dump (254-258)
  • model_validate (261-265)
tests/main/test_public_api_signature_baseline.py (1)
src/datamodel_code_generator/config.py (2)
  • GenerateConfig (85-217)
  • ParserConfig (390-568)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py

358-358: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


369-369: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


613-613: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


614-614: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


616-616: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


617-617: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


620-620: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__main__.py

42-42: Unused noqa directive (non-enabled: TC003)

Remove unused noqa directive

(RUF100)


175-175: Unused noqa directive (non-enabled: N805)

Remove unused noqa directive

(RUF100)


500-500: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


501-501: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


503-503: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


504-504: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


505-505: Unused noqa directive (non-enabled: UP045)

Remove unused noqa directive

(RUF100)


587-587: Unused noqa directive (non-enabled: PLR0913)

Remove unused noqa directive

(RUF100)


727-727: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


729-729: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


748-748: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


750-750: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


751-751: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1022-1022: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


1029-1029: Unused noqa directive (non-enabled: T201)

Remove unused noqa directive

(RUF100)


1132-1132: Unused noqa directive (non-enabled: T201)

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). (13)
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.12 on macOS
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.10 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 (34)
pyproject.toml (1)

247-307: Coverage omit entries and profiles look consistent with new config types

The additional run.omit patterns for _types modules and the four new tool.datamodel-codegen.profiles.* sections (generate/parser/parse/cli config dicts) reference existing classes and enums and match the refactored config layout. No issues spotted here.

tests/main/test_main_general.py (8)

5-7: New imports are minimal and appropriately scoped

io and json are only used in the new config/CLI validation tests and keep dependencies light. Nothing to change.


27-32: Direct imports of config and parser classes align with public API

Importing GenerateConfig, ParseConfig, ParserConfig, and the parser classes matches the new config-driven public surface and keeps tests close to the intended usage. Looks good.


108-132: Config file-field validators are well covered

The tests for extra_template_data handling (None, dict, text IO, invalid path) correctly exercise Config.validate_file. They assert both successful coercions and failure on non-files, which is exactly what the validator does. No issues.


134-173: CLI rejection tests for invalid JSON-like inputs are precise

The three tests around invalid extra_template_data, aliases, and custom_formatters_kwargs files correctly simulate bad structures and assert Exit.ERROR. These align with the new error-printing paths in __main__.py and should prevent silent failures. No problems seen.


200-221: generate(): mutual-exclusivity and mapping support are validated

  • test_generate_rejects_config_and_options asserts the ValueError when mixing config and individual options.
  • test_generate_accepts_config_mapping checks a plain mapping config path returns None (since an output file is given).

Both match the intended API and will catch regressions in argument handling.


223-250: Base Parser config handling tests are robust

The DummyParser tests verify:

  • Raising when config and extra options are mixed.
  • Accepting both ParserConfig instances and config mappings.
    This mirrors the intended constructor contract and uses parse_raw() as a no-op to exercise the path. Looks correct.

252-265: ParseConfig usage in Parser.parse() is correctly constrained

The tests ensure parse(config=ParseConfig(), with_import=True) raises and that a plain mapping for config is accepted and returns a truthy result. This matches the new parse signature semantics.


267-325: Per-parser config mixing tests cover key subclasses

The GraphQL, JsonSchema, and OpenAPI parser tests consistently:

  • Reject config + options combinations.
  • Accept config mappings and assert a representative attribute (e.g., use_standard_collections, base_path, open_api_scopes) is initialized.

This gives good coverage of the subclass constructors and their config wiring.

tests/main/test_public_api_direct.py (5)

9-22: Imports and fixtures reflect the intended public API

This module correctly imports GenerateConfig, ParserConfig, parser classes, and expected/fixture paths, aligning the tests with the documented public surface rather than internal helpers. Good baseline for API stability.


27-56: GENERATE_CASES comprehensively exercise main input types

The three generate cases (JSON Schema, OpenAPI, GraphQL) use realistic options and expected outputs. Using extra_fields="forbid" for OpenAPI is in line with existing behavior. This table-driven approach looks solid.


59-91: PARSER_CASES mirror generate cases and use appropriate options

The parser cases pass only parser-relevant options (use_standard_collections, use_union_operator, extra_fields) and pair them with expected generated files. This keeps the public Parser API coverage in sync with generate() coverage.


94-111: generate() public API test correctly switches between config and kwargs

The use_config flag toggles between constructing GenerateConfig(**options) and passing **options directly, then normalizes trailing newlines before comparing with assert_output. This is a concise but effective regression test for the new config parameter.


113-153: Parser public API test handles headers and forward-ref noise cleanly

The parser test:

  • Exercises both ParserConfig objects and kwargs.
  • Strips the autogenerated header region.
  • Normalizes line endings.
  • Removes trailing .update_forward_refs() calls via _strip_update_forward_refs.

This avoids brittle comparisons while still asserting semantic equivalence to golden files. Well structured.

tests/main/test_public_api_signature_baseline.py (1)

8-37: Baselines accurately document the new config-driven signatures

_baseline_generate and _BaselineParser.__init__ now capture the intended public signatures (config plus **options: Unpack[...]), and the tests compare both keyword-only parameter sets and annotations against the real APIs. This is a good guardrail against future breaking changes.

src/datamodel_code_generator/config.py (6)

40-57: TYPE_CHECKING branches and fallbacks look safe

The TYPE_CHECKING vs runtime sections correctly:

  • Import precise types when type checking.
  • Fall back to Any for Path/ParseResult/DataModel/etc. under Pydantic v1 to avoid import cycles.
  • Treat UnionMode as Any at runtime when not available.

This balances type safety with cyclic-import resilience.

Please ensure your current Pydantic v1/v2 matrix still type-checks with these aliases (e.g. run pyright/mypy) to catch any missed forward refs.


76-83: TypedDict alias wiring matches generated types

The aliases GenerateConfigDict, ParseConfigDict, and ParserConfigDict correctly refer to the generated _types modules, keeping Pydantic models and the TypedDict schemas in sync. This is important for the Unpack[...] signatures used elsewhere.


85-217: GenerateConfig model mirrors existing CLI/generate options

The GenerateConfig fields align with the options exposed in the CLI and TypedDict definitions, and the Pydantic v1/v2 configuration (extra="forbid", arbitrary_types_allowed=True) is consistent. No obvious mismatches or missing flags based on the provided _types snippets.

Given the size of this model, it’s worth running your existing config-serialization tests (and the new dict-generation profiles) to confirm all fields round-trip correctly between CLI, GenerateConfig, and the generated GenerateConfigDict.


220-356: CliConfigSchema cleanly separates CLI-only concerns from core GenerateConfig

CliConfigSchema deliberately includes CLI-only flags (check/debug/watch/etc.) while reusing the same shapes as GenerateConfig for shared options. Using a Field(default_factory=...) for openapi_scopes is a good choice to avoid mutable-default pitfalls. The v1/v2 config handling mirrors GenerateConfig and looks consistent.


390-568: ParserConfig._from_generate_config correctly derives parser settings

Key aspects look right:

  • Derives effective_dataclass_arguments from GenerateConfig.dataclass_arguments plus frozen_dataclasses/keyword_only.
  • Forces enum_field_as_literal = LiteralType.All when outputting TypedDicts.
  • Forces set_default_enum_member=True for dataclasses output.
  • Uses model_dump with field-set intersection and then enriches via _build_parser_config_overrides.
  • Validates via model_validate with a filtered dict keyed by actual parser fields.

This should keep parser behavior in sync with generate() while retaining Pydantic v1/v2 compatibility.

It would be good to run a few end-to-end tests that compare ParserConfig produced via _from_generate_config with manually constructed ParserConfig objects, to ensure no important fields are omitted from the intersection logic.


571-604: ParseConfig and its conversion helper are minimal and focused

ParseConfig only tracks flags relevant to Parser.parse(), and _from_generate_config uses the same intersection pattern as ParserConfig. This keeps the parse-time config surface intentionally small and driven by GenerateConfig.

src/datamodel_code_generator/__main__.py (13)

42-50: New typing/pydantic imports are appropriate

Importing Mapping, Sequence, BaseModel, Field, and ValidationError here is justified by the new Config model and error handling paths. No redundancy or obvious overreach.


143-188: Config.validate_file provides flexible, well-bounded coercion

The validate_file validator:

  • Accepts None, dict, text IO, and string/Path-like values.
  • Loads JSON via json.load/json.loads and raises Error when the path is not a file, matching the new tests.
    One minor nuance: Path(value) will accept non-str value (e.g. Path itself) but that’s OK since isinstance(value, dict)/TextIOBase are checked first. This is fine.

255-309: Pre-validators for CLI string options are straightforward and compatible

The model_validator(mode="before") methods to split comma-separated additional_imports, custom_formatters, parse JSON for duplicate_name_suffix, migrate parent_scoped_naming, and normalize class_decorators keep CLI convenience while feeding structured data into the underlying config. Error messages (e.g., invalid JSON string) are clear.


330-442: Output/time/naming/all-exports validators mirror existing behavior

The v2 vs v1 branches of validators enforce:

  • output_datetime_class constraints for dataclasses.
  • original_field_name_delimiter requiring snake_case_field.
  • mutual exclusivity for custom file header options.
  • keyword_only vs target Python version.
  • use_annotated implying field_constraints.
  • all_exports_collision_strategy requiring recursive scope.

These behaviors are consistent with the rest of the codebase and the tests in test_main_general.py.


443-565: Config inherits GenerateConfig cleanly while adding CLI-only surface

The dataclass-style field definitions on Config match or specialize those in GenerateConfig:

  • Shared fields keep compatible types (often narrowed to Optional[...] for CLI parsing).
  • CLI-only fields (input/input_model/check/debug/watch/etc.) remain local to Config and are later stripped in to_generate_config.

Using Mapping/Sequence for aliases/strict_types is consistent with how validators treat them. Looks correct.


567-585: merge_args correctly merges namespace into Config with validation

The method:

  • Collects only attributes present on args and not None.
  • Applies two derived flags (use_annotatedfield_constraints) later in main, not here.
  • Re-parses via Config.parse_obj to re-run validators, then assigns validated values.

This keeps CLI parsing robust and leverages Pydantic validation without duplicating logic.


630-641: _extract_additional_imports mutates template data by design

The helper both:

  • Extracts and normalizes additional_imports and
  • Pops them out of the extra_template_data entries.

Given it’s only called after a copy (defaultdict(dict, **config.extra_template_data)), this is safe and keeps template data clean for later rendering. Behavior matches new tests.


700-761: _load_model_schema’s config-model rebuild and Pydantic v2 handling are solid

Enhancements here:

  • Optionally calls a module-level _rebuild_config_models() if present, allowing imported config modules to resolve forward refs lazily.
  • Suppresses noisy PydanticJsonSchemaWarning when calling model_json_schema() or TypeAdapter(...).json_schema() with warnings filters.

The rest of the function’s error messages are explicit and user-friendly. No functional issues spotted.

Please run the new --input-model paths against both dict and Pydantic model targets in your test matrix to confirm _rebuild_config_models() behaves as expected when importing config modules.


764-804: pyproject profile merging is correct and supports profiles gracefully

_get_pyproject_toml_config:

  • Walks upwards to find the nearest pyproject.toml.
  • Merges a named profile over the base [tool.datamodel-codegen] config.
  • Produces CLI/Config-friendly keys by replacing - with _.
  • Provides clear errors when profile is missing or pyproject absent.

This underpins the new TypedDict-generation profiles and looks good.


940-960: run_generate_from_config correctly funnels through GenerateConfig

The wrapper:

  • Calls config.to_generate_config(...) with validated mappings and paths.
  • Passes config=generate_config into generate() instead of individual options.
  • Still respects output handling via the returned GenerateConfig.

This keeps the main function from duplicating config-mapping logic and is consistent with new tests rejecting mixed config/options usage.


1021-1031: Config parsing now handles both Error and ValidationError uniformly

Wrapping parsing and _rebuild_config_models() in a try/except that catches both Error and ValidationError and prints a single string message gives clearer feedback when pyproject/CLI config fails validation. This matches the new tests around invalid values.


1125-1171: Improved validation and error messages for template/alias/formatter mappings

The new blocks:

  • Wrap extra_template_data defaultdict coercion in a try/except and print a clear message on structural errors.
  • Ensure aliases and custom_formatters_kwargs are dicts with string keys/values before proceeding, with explicit stderr messages when invalid.

These changes directly address prior review feedback and are well covered by tests in test_main_general.py.


1186-1205: run_generate_from_config integration respects new mappings

The call to run_generate_from_config now passes:

  • extra_template_data (possibly None or a defaultdict),
  • aliases,
  • custom_formatters_kwargs,
  • settings_path=config.output.

This keeps all derived mappings flowing through the same translation layer. Using settings_path=config.output makes sense given formatter/Black/ruff should honor the output location’s pyproject.


def test_main_aliases_with_pydantic_v1_config(tmp_path: Path) -> None:
"""Exercise pydantic v1 config branches for coverage."""
import datamodel_code_generator.config as config_module

Check notice

Code scanning / CodeQL

Module is imported with 'import' and 'import from' Note test

Module 'datamodel_code_generator.config' is imported with both 'import' and 'import from'.

Copilot Autofix

AI 4 months ago

In general, to fix this issue you should avoid importing the same module with both import xxx and from xxx import yyy. Keep the from ... import ... form (as recommended) and, where you need module-style access, bind the module object via that existing import, e.g. import package as _pkg; module = _pkg.module or similar, or import the module directly from the package that is already imported.

In this specific case, we already import from the top of the file:

from datamodel_code_generator.config import GenerateConfig, ParseConfig, ParserConfig

but inside test_main_aliases_with_pydantic_v1_config we do:

import datamodel_code_generator.config as config_module
from datamodel_code_generator import util

The fix is to remove the inner import datamodel_code_generator.config as config_module and instead import the top-level datamodel_code_generator package once at the module level so that we can refer to datamodel_code_generator.config in the test. That preserves behavior while avoiding the duplicate style of importing the same submodule. Concretely:

  • At the top of tests/main/test_main_general.py, add import datamodel_code_generator.
  • In test_main_aliases_with_pydantic_v1_config, remove the import datamodel_code_generator.config as config_module line.
  • Replace uses of config_module in that test with datamodel_code_generator.config.

No additional methods or definitions are required; only imports and name references change.

Suggested changeset 1
tests/main/test_main_general.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/main/test_main_general.py b/tests/main/test_main_general.py
--- a/tests/main/test_main_general.py
+++ b/tests/main/test_main_general.py
@@ -11,6 +11,7 @@
 import pytest
 from inline_snapshot import snapshot
 
+import datamodel_code_generator
 from datamodel_code_generator import (
     AllExportsScope,
     DataModelType,
@@ -164,13 +165,12 @@
 
 def test_main_aliases_with_pydantic_v1_config(tmp_path: Path) -> None:
     """Exercise pydantic v1 config branches for coverage."""
-    import datamodel_code_generator.config as config_module
     from datamodel_code_generator import util
 
     if util.is_pydantic_v2():
         pytest.skip("pydantic v1-only coverage")
-    assert config_module.Path is config_module.Any
-    config_module._rebuild_config_models()
+    assert datamodel_code_generator.config.Path is datamodel_code_generator.config.Any
+    datamodel_code_generator.config._rebuild_config_models()
     run_main_and_assert(
         input_path=JSON_SCHEMA_DATA_PATH / "person.json",
         output_path=tmp_path / "out.py",
EOF
@@ -11,6 +11,7 @@
import pytest
from inline_snapshot import snapshot

import datamodel_code_generator
from datamodel_code_generator import (
AllExportsScope,
DataModelType,
@@ -164,13 +165,12 @@

def test_main_aliases_with_pydantic_v1_config(tmp_path: Path) -> None:
"""Exercise pydantic v1 config branches for coverage."""
import datamodel_code_generator.config as config_module
from datamodel_code_generator import util

if util.is_pydantic_v2():
pytest.skip("pydantic v1-only coverage")
assert config_module.Path is config_module.Any
config_module._rebuild_config_models()
assert datamodel_code_generator.config.Path is datamodel_code_generator.config.Any
datamodel_code_generator.config._rebuild_config_models()
run_main_and_assert(
input_path=JSON_SCHEMA_DATA_PATH / "person.json",
output_path=tmp_path / "out.py",
Copilot is powered by AI and may make mistakes. Always verify output.
@koxudaxi koxudaxi marked this pull request as draft December 28, 2025 14:28
@koxudaxi koxudaxi closed this Dec 28, 2025
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 1, 2026

📢 Related PR Released: 0.51.0

PR #2832, which references this PR, has been released. See the release notes for details.

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.

2 participants