Conversation
📝 WalkthroughWalkthroughParsers were refactored to use config-driven initialization: new ParserConfig variants (OpenAPIParserConfig, GraphQLParserConfig) and ParseConfig extensions; Parser and parser subclasses accept Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Caller as Caller
participant ParserSub as ParserSubclass
participant ParserBase as ParserBase
participant Config as ParserConfig
Note over Caller,Config: Caller may pass a config object and/or explicit options
Caller->>ParserSub: instantiate(source, config?, **options)
alt config provided
ParserSub->>Config: validate/rebuild config (model_validate/model_rebuild)
alt options present
ParserSub->>Config: merge options into config (options take precedence)
end
else no config
ParserSub->>Config: Config.from_options(options)
end
ParserSub->>ParserBase: super().__init__(source, config=config)
ParserBase->>Config: read resolved fields (types, flags, templates, imports)
ParserBase->>ParserBase: set internal attributes from config
ParserBase-->>ParserSub: initialized state
ParserSub-->>Caller: ready parser instance
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
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. Comment |
|
📚 Docs Preview: https://pr-2863.datamodel-code-generator.pages.dev |
CodSpeed Performance ReportMerging #2863 will not alter performanceComparing
|
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/datamodel_code_generator/parser/openapi.py (1)
57-63: Config-basedtarget_datetime_classwill be ignored due to premature default assignmentThe config merging for
openapi_scopes,include_path_parameters, anduse_status_code_in_response_nameis correct. However, there's a critical issue withtarget_datetime_classhandling:At line 312:
target_datetime_class = target_datetime_class or DatetimeClassType.AwaredatetimeThis default is applied before calling
super().__init__(). The parentParser.__init__(in base.py) attempts to mergeconfig.target_datetime_class, but only when the parameter isNone:target_datetime_class = ( config.target_datetime_class if target_datetime_class is None else target_datetime_class )Since line 312 already set
target_datetime_classtoAwaredatetimewhen it wasNone, the parent's config check fails, and anyconfig.target_datetime_classvalue is silently ignored.To fix this, read from config before applying the default:
if config is not None and target_datetime_class is None: target_datetime_class = config.target_datetime_class target_datetime_class = target_datetime_class or DatetimeClassType.AwaredatetimeThis same issue exists in
JsonSchemaParser.
🧹 Nitpick comments (2)
tests/main/test_public_api_signature_baseline.py (1)
609-737: Config-backed parser tests give good coverage; consider de-duplicating the setupThe three new tests for
JsonSchemaParser,OpenAPIParser, andGraphQLParsernicely verify that:
ParserConfig/OpenAPIParserConfig/GraphQLParserConfigcan be rebuilt with a_types_namespaceand instantiated.- Passing
config=...wires values into parser attributes (includingextra_template_dataand parser‑specific options).The repeated
model_rebuild(_types_namespace=...)blocks are very similar to the existingGenerateConfigtest. If this pattern keeps growing, you might want a tiny shared helper to rebuild any config model with the common namespace, but that’s optional.src/datamodel_code_generator/parser/graphql.py (1)
56-61: GraphQL-specific config precedence is sensible and preserves explicit overridesThe new
config: GraphQLParserConfig | None = Noneparameter plus:if config is not None: if config.data_model_scalar_type is not None and data_model_scalar_type is DataTypeScalar: data_model_scalar_type = config.data_model_scalar_type if config.data_model_union_type is not None and data_model_union_type is DataTypeUnion: data_model_union_type = config.data_model_union_typegive a clear precedence model:
- If callers stick with the default
DataTypeScalar/DataTypeUnion, aGraphQLParserConfigcan override both types.- If they pass custom
data_model_scalar_type/data_model_union_typeexplicitly, those are respected (no override because theis DataTypeScalar/DataTypeUnionchecks fail).Passing
config=configintosuper().__init__and then assigningself.data_model_scalar_type/self.data_model_union_typeafter the base initializer keeps GraphQL-specific concerns isolated from the baseParserwhile still exposing the chosen types to parsing methods. This looks correct.One minor edge case: if someone explicitly passes
data_model_scalar_type=DataTypeScalarand sets a differentdata_model_scalar_typeinGraphQLParserConfig, the config will win. That seems acceptable, but it might be worth documenting that “config beats default-like explicit args” if this pattern is used elsewhere.Also applies to: 104-232
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/datamodel_code_generator/config.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pytests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧬 Code graph analysis (4)
src/datamodel_code_generator/parser/graphql.py (3)
src/datamodel_code_generator/config.py (1)
GraphQLParserConfig(325-329)src/datamodel_code_generator/model/scalar.py (1)
DataTypeScalar(94-99)src/datamodel_code_generator/model/union.py (1)
DataTypeUnion(66-74)
src/datamodel_code_generator/parser/openapi.py (2)
src/datamodel_code_generator/config.py (1)
OpenAPIParserConfig(317-322)src/datamodel_code_generator/format.py (1)
DatetimeClassType(50-57)
src/datamodel_code_generator/parser/base.py (1)
src/datamodel_code_generator/config.py (1)
ParserConfig(192-314)
src/datamodel_code_generator/parser/jsonschema.py (1)
src/datamodel_code_generator/config.py (1)
ParserConfig(192-314)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
690-690: Unused noqa directive (non-enabled: PLR0912, PLR0913, PLR0914, PLR0915)
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-black24 on Ubuntu
- GitHub Check: 3.10 on Windows
- GitHub Check: py312-black22 on Ubuntu
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.12 on macOS
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.13 on macOS
- GitHub Check: Analyze (python)
- GitHub Check: benchmarks
🔇 Additional comments (5)
src/datamodel_code_generator/parser/base.py (2)
85-85: LGTM! Clean addition of config parameter.The TYPE_CHECKING import and optional config parameter are well-designed:
- Avoids circular imports by using TYPE_CHECKING
- Maintains backward compatibility with optional parameter
- Allows dependency injection of configuration
Also applies to: 694-694
690-690: Remove unusednoqadirective.Ruff reports that the complexity suppressions on line 690 are not needed:
def __init__( # noqa: PLR0012, PLR0013, PLR0014, PLR0915These Pylint codes (too many branches/arguments/locals/statements) are either not enabled in your configuration or not triggered at the current thresholds.
🔎 Proposed fix
Remove the unused
noqadirective:- def __init__( # noqa: PLR0912, PLR0913, PLR0914, PLR0915 + def __init__( self, source: str | Path | list[Path] | ParseResult | dict[str, YamlValue], *,If these suppressions are needed in the future, Ruff will warn you to add them back.
⛔ 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:22.481Z 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.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.tests/main/test_public_api_signature_baseline.py (1)
181-187: Baseline parser now modelsconfigparameter correctlyAdding
config: ParserConfig | None = Noneto_BaselineParser.__init__keeps the test harness aligned with the realParser.__init__signature and withParserConfig’s field set/defaults used in the config‑vs‑signature tests below. No issues here.src/datamodel_code_generator/config.py (2)
317-323: OpenAPIParserConfig cleanly scopes OpenAPI-only parser optionsDefining
OpenAPIParserConfig(ParserConfig)with:openapi_scopes: list[OpenAPIScope] | None = None include_path_parameters: bool = False use_status_code_in_response_name: bool = Falsematches the corresponding
OpenAPIParser.__init__kwargs and keeps these options out of the genericParserConfig. This gives a nice separation between shared parser configuration and OpenAPI-specific behavior without changing validation rules.
325-330: GraphQLParserConfig correctly mirrors GraphQL-specific type hooks
GraphQLParserConfig(ParserConfig)adds:data_model_scalar_type: type[DataModel] | None = None data_model_union_type: type[DataModel] | None = Nonewhich align with
GraphQLParser.__init__’sdata_model_scalar_type/data_model_union_typekwargs and with the new tests that rebuild the model with a_types_namespace. These fields stay out of the baseParserConfig, keeping specialization clear while still allowing a single config object to be passed intoGraphQLParser.
🤖 Generated by GitHub Actions
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #2863 +/- ##
==========================================
- Coverage 99.38% 99.34% -0.05%
==========================================
Files 91 91
Lines 15555 15773 +218
Branches 1827 1855 +28
==========================================
+ Hits 15460 15670 +210
- Misses 50 55 +5
- Partials 45 48 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tests/main/test_public_api_signature_baseline.py (1)
403-426:test_parser_config_defaults_match_parser_signaturehas become effectively a no-opWith
_BaselineParser.__init__now only exposingconfigas a kw-only parameter,expected_paramsin this test contains just"config", whileParserConfig.model_fieldshas no field by that name. Theforloop therefore never performs any assertions, despite the docstring claiming it checks defaults againstParser.__init__.Consider either:
- Updating the test to assert some concrete property of how
ParserConfigdefaults are applied (e.g., instantiatingParserwith an emptyParserConfigand checking selected attributes), or- Removing/renaming this test and its docstring so it doesn’t suggest behavior that no longer occurs.
src/datamodel_code_generator/parser/base.py (1)
700-829: Excellent refactoring to config-driven initialization.This refactoring significantly improves the maintainability and usability of the
Parserclass:
- Cleaner API: Single
configparameter replaces ~90 individual keyword arguments- Consistent precedence: The
opt()wrapper ensures explicitoptions > config > defaultsthroughout- Backward compatible: Still accepts
**optionsfor per-call overrides- Reduced duplication: Centralized option resolution eliminates repetitive conditional logic
The
extra_template_datahandling (lines 827-829) correctly ensures it's converted to adefaultdictwhen needed, maintaining the expected behavior.Based on learnings, the previous repetitive config override logic has been successfully replaced with this cleaner pattern as noted in past review comments.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
docs/cli-reference/model-customization.mddocs/cli-reference/template-customization.mdsrc/datamodel_code_generator/config.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pytests/main/test_public_api_signature_baseline.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/datamodel_code_generator/config.py
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-12-25T09:23:08.506Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:23:08.506Z
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:
tests/main/test_public_api_signature_baseline.py
📚 Learning: 2025-12-25T09:22:22.481Z
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:22.481Z
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/parser/base.py
🧬 Code graph analysis (3)
tests/main/test_public_api_signature_baseline.py (2)
src/datamodel_code_generator/config.py (3)
ParserConfig(194-316)OpenAPIParserConfig(319-324)GraphQLParserConfig(327-331)src/datamodel_code_generator/parser/__init__.py (1)
LiteralType(20-25)
src/datamodel_code_generator/parser/graphql.py (4)
src/datamodel_code_generator/format.py (1)
DatetimeClassType(50-57)src/datamodel_code_generator/parser/__init__.py (1)
LiteralType(20-25)src/datamodel_code_generator/parser/base.py (2)
Parser(693-3201)_get_option(83-95)src/datamodel_code_generator/config.py (1)
GraphQLParserConfig(327-331)
src/datamodel_code_generator/parser/openapi.py (3)
src/datamodel_code_generator/format.py (1)
DatetimeClassType(50-57)src/datamodel_code_generator/parser/base.py (3)
_get_option(83-95)get_special_path(295-297)parse(3121-3201)src/datamodel_code_generator/config.py (1)
OpenAPIParserConfig(319-324)
🪛 GitHub Check: CodeQL
src/datamodel_code_generator/parser/base.py
[notice] 74-74: Cyclic import
Import of module datamodel_code_generator.types begins an import cycle.
[notice] 80-80: Cyclic import
Import of module datamodel_code_generator.config begins an import cycle.
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
700-700: Unused noqa directive (non-enabled: PLR0912, PLR0914, PLR0915)
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). (1)
- GitHub Check: combine coverage
🔇 Additional comments (16)
docs/cli-reference/model-customization.md (1)
1371-1379: Literal-typedApi.versionexample is consistent and correctImporting
Literaland annotatingversionasLiteral['v1']while keepingField('v1', const=True, ...)accurately documents a constant string field and stays consistent with the surrounding Pydantic v2 and TypedDict/msgspec examples.docs/cli-reference/template-customization.md (1)
2556-2557: MapState Literal types correctly mirror schema consts and double-quote behaviorSwitching
map_view_mode,map_split_mode, andis_splittoLiteral[...]with matching const defaults and aliases is consistent with the input schema and clearly demonstrates--use-double-quotesoutput; no issues spotted.Also applies to: 2562-2578
tests/main/test_public_api_signature_baseline.py (4)
30-46: Baseline parser stub now correctly models theconfig-centric public APIImporting
Parser/YamlValueand updating_BaselineParser.__init__to acceptsourceplus a kw-onlyconfig: ParserConfig | None = None(with**options: Any) matches the new constructor shape forParser.__init__. The existing signature test will keep theconfigkw-only parameter in sync without over-constraining the internal options surface.Also applies to: 177-185
497-537: JsonSchemaParser–ParserConfig integration test is well targetedThe
test_jsonschema_parser_with_configcase:
- Rebuilds
ParserConfigwith the appropriate_types_namespacefor forward refs.- Passes key options (
validation,snake_case_field,use_schema_description,reuse_model, andextra_template_data) viaParserConfig.- Asserts that the resulting
JsonSchemaParserinstance exposes these attributes and thatextra_template_datais preserved.This provides a solid sanity check that the new config-based initialization path behaves as expected for the JSON Schema parser.
540-582: OpenAPIParserConfig test exercises OpenAPI-specific options correctly
test_openapi_parser_with_config:
- Rebuilds
OpenAPIParserConfigwith the necessary type namespace.- Verifies that
validation,snake_case_field,openapi_scopes,include_path_parameters, anduse_status_code_in_response_nameset on the config are reflected on theOpenAPIParserinstance.This is a good focused check that the OpenAPI-specific configuration surface is correctly wired through the new
configparameter.
585-624: GraphQLParserConfig test cleanly validates scalar/union type overrides
test_graphql_parser_with_config:
- Rebuilds
GraphQLParserConfigfor forward refs.- Asserts that
validationandsnake_case_fieldpropagate, and thatdata_model_scalar_type/data_model_union_typeonGraphQLParserare exactly the configuredDataTypeScalarandDataTypeUnionclasses.This gives good coverage that GraphQL-specific parser behavior is correctly driven by the new config model.
src/datamodel_code_generator/parser/jsonschema.py (2)
84-86: LGTM!The TYPE_CHECKING imports are correctly updated to include
ParserConfigfor type hints without runtime impact.
627-638: LGTM! The config-driven initialization is correctly implemented.The
target_datetime_classdefault handling now properly respects the precedence: explicit options > config > default. The condition at lines 635-636 correctly checks both sources before applying the fallback.src/datamodel_code_generator/parser/openapi.py (3)
27-28: LGTM!Import changes correctly add
DatetimeClassType,_get_option, andget_special_pathfor the config-driven initialization and existing functionality.Also applies to: 35-35
41-42: LGTM!TYPE_CHECKING imports correctly updated to include
OpenAPIParserConfigandDataModelFieldBasefor type hints.
165-188: LGTM! The OpenAPI config-driven initialization is well-structured.The implementation correctly:
- Uses
_get_optionto resolve OpenAPI-specific options with proper precedence (options > config > default)- Applies the same
target_datetime_classdefault pattern asJsonSchemaParser- Forwards config to the base class via
super().__init__- Sets instance attributes after parent initialization
src/datamodel_code_generator/parser/graphql.py (3)
16-17: LGTM!Import reorganization correctly adds necessary imports for the config-driven initialization pattern:
DatetimeClassType,LiteralType,_get_option, andTypes.Also applies to: 23-23, 28-28, 32-32
42-45: LGTM!TYPE_CHECKING imports correctly updated to include
GraphQLParserConfigand related types for type hints.
89-111: LGTM! The GraphQL config-driven initialization follows the established pattern.The implementation correctly uses
_get_optionto resolve GraphQL-specific options with proper precedence. Note thatDatetimeClassType.Datetimeis used as the default here, whereas JSON Schema and OpenAPI parsers useDatetimeClassType.Awaredatetime- this appears intentional for GraphQL's different datetime handling conventions.Please confirm the intentional difference in default
target_datetime_classbetween parsers:
- GraphQLParser:
DatetimeClassType.Datetime- JsonSchemaParser/OpenAPIParser:
DatetimeClassType.Awaredatetimesrc/datamodel_code_generator/parser/base.py (2)
77-81: Cyclic import warnings are false positives.The static analysis tool flags cyclic imports on lines 74 and 80, but these are not problematic at runtime because:
- The
ParserConfigimport on line 80 is guarded byTYPE_CHECKING, which isFalseat runtime- This is the standard pattern for avoiding runtime import cycles while preserving type hints for static analysis
The warnings can be safely ignored.
83-95: LGTM! Clean option resolution with correct precedence.The
_get_optionhelper correctly implements the documented precedence (options > config > default) and provides a clean abstraction for resolving configuration values throughout the__init__method.
- Remove _get_option helper function from base.py - Use ParserConfig.model_validate(options) to convert options to config - Update all instance variable references to use config.xxx pattern - Apply same pattern to JsonSchemaParser, OpenAPIParser, GraphQLParser - Fix aliases type from Mapping[str, str] to Mapping[str, str | list[str]] to support multiple aliases per field - Add model_rebuild() calls to resolve forward references before validation 🤖 Generated with [Claude Code](https://claude.com/claude-code)
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/datamodel_code_generator/parser/base.py (1)
685-685: Remove unusednoqadirective.The
noqadirective forPLR0912, PLR0914, PLR0915is no longer needed as these complexity rules are not enabled in the linting configuration.🔎 Proposed fix
- def __init__( # noqa: PLR0912, PLR0915 + def __init__(
🧹 Nitpick comments (4)
src/datamodel_code_generator/parser/graphql.py (1)
110-118: Optional refactor: clarify intent when clearing options.Lines 112 and 118 set
options = {}after merging them into config, but the variable is then unused (flagged by static analysis). Consider usingdel optionsor assigning to_to make the intent clearer:🔎 Proposed refactor
if config is None: config = GraphQLParserConfigClass.model_validate(options) - options = {} # Clear options since they're now in config elif options: # Merge options into config (options take precedence) config_dict = config.model_dump() config_dict.update(options) config = GraphQLParserConfigClass.model_validate(config_dict) - options = {} # Clear options since they're now in configOr if you want to be explicit:
config = GraphQLParserConfigClass.model_validate(config_dict) - options = {} # Clear options since they're now in config + del options # Options have been merged into configsrc/datamodel_code_generator/parser/openapi.py (1)
187-195: Optional refactor: clarify intent when clearing options.Lines 189 and 195 set
options = {}after processing, but the variable is unused afterward (flagged by static analysis). Same issue as ingraphql.py. Consider usingdel optionsor removing the assignments to clarify intent.🔎 Proposed refactor
if config is None: config = OpenAPIParserConfigClass.model_validate(options) - options = {} # Clear options since they're now in config elif options: # Merge options into config (options take precedence) config_dict = config.model_dump() config_dict.update(options) config = OpenAPIParserConfigClass.model_validate(config_dict) - options = {} # Clear options since they're now in configsrc/datamodel_code_generator/parser/jsonschema.py (2)
635-647: Local imports are intentional but flagged by linting.The imports inside
__init__are placed here to avoid circular imports and to provide the type namespace formodel_rebuild(). This is a valid pattern, but the pipeline is failing withPLC0415(imports should be at top-level).Consider suppressing the lint rule for these specific lines if this pattern is intentional:
🔎 Suggested inline suppression
- from datamodel_code_generator.config import ParserConfig as ParserConfigClass - from datamodel_code_generator.model.base import DataModel, DataModelFieldBase - from datamodel_code_generator.types import DataTypeManager, StrictTypes + from datamodel_code_generator.config import ParserConfig as ParserConfigClass # noqa: PLC0415 + from datamodel_code_generator.model.base import DataModel, DataModelFieldBase # noqa: PLC0415 + from datamodel_code_generator.types import DataTypeManager, StrictTypes # noqa: PLC0415
649-657: Remove unusedoptions = {}assignments.The static analysis correctly identifies that
optionsis assigned to{}on lines 651 and 657 but never used afterward. These assignments are dead code and can be safely removed.🔎 Proposed fix
if config is None: config = ParserConfigClass.model_validate(options) - options = {} # Clear options since they're now in config elif options: # Merge options into config (options take precedence) config_dict = config.model_dump() config_dict.update(options) config = ParserConfigClass.model_validate(config_dict) - options = {} # Clear options since they're now in config
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/datamodel_code_generator/__init__.pysrc/datamodel_code_generator/_types/generate_config_dict.pysrc/datamodel_code_generator/_types/parser_config_dict.pysrc/datamodel_code_generator/config.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pysrc/datamodel_code_generator/reference.py
🚧 Files skipped from review as they are similar to previous changes (1)
- src/datamodel_code_generator/config.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:22:22.481Z
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:22.481Z
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/parser/base.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/parser/base.py
📚 Learning: 2025-12-25T09:23:08.506Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:23:08.506Z
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/parser/base.py
🧬 Code graph analysis (2)
src/datamodel_code_generator/parser/graphql.py (4)
src/datamodel_code_generator/format.py (1)
DatetimeClassType(50-57)src/datamodel_code_generator/parser/__init__.py (1)
LiteralType(20-25)src/datamodel_code_generator/config.py (1)
GraphQLParserConfig(327-331)src/datamodel_code_generator/parser/jsonschema.py (1)
model_rebuild(215-217)
src/datamodel_code_generator/parser/base.py (3)
src/datamodel_code_generator/util.py (1)
camel_to_snake(248-251)src/datamodel_code_generator/config.py (1)
ParserConfig(194-316)src/datamodel_code_generator/parser/jsonschema.py (1)
model_rebuild(215-217)
🪛 GitHub Actions: Lint
src/datamodel_code_generator/parser/graphql.py
[error] 96-98: PL C0415 import should be at the top-level of a file
src/datamodel_code_generator/parser/openapi.py
[error] 173-175: PL C0415 import should be at the top-level of a file
[error] 173-175: PLC0415 import should be at the top-level of a file
src/datamodel_code_generator/parser/jsonschema.py
[error] 635-637: PL C0415 import should be at the top-level of a file
[error] 635-637: PLC0415 import should be at the top-level of a file
[error] 636-638: PLC0415 import should be at the top-level of a file
src/datamodel_code_generator/parser/base.py
[error] 690-692: PL C0415 import should be at the top-level of a file
[error] 688-692: PLC0415 import should be at the top-level of a file
[error] 689-691: PLC0415 import should be at the top-level of a file
[error] 690-692: PLC0415 import should be at the top-level of a file
🪛 GitHub Check: CodeQL
src/datamodel_code_generator/parser/graphql.py
[notice] 112-112: Unused local variable
Variable options is not used.
[notice] 118-118: Unused local variable
Variable options is not used.
src/datamodel_code_generator/parser/openapi.py
[notice] 189-189: Unused local variable
Variable options is not used.
[notice] 195-195: Unused local variable
Variable options is not used.
src/datamodel_code_generator/parser/jsonschema.py
[notice] 651-651: Unused local variable
Variable options is not used.
[notice] 657-657: Unused local variable
Variable options is not used.
src/datamodel_code_generator/parser/base.py
[notice] 74-74: Cyclic import
Import of module datamodel_code_generator.types begins an import cycle.
[notice] 74-74: Unused import
Import of 'DataTypeManager' is not used.
[notice] 693-693: Cyclic import
Import of module datamodel_code_generator.config begins an import cycle.
[notice] 694-694: Cyclic import
Import of module datamodel_code_generator.model.base begins an import cycle.
[notice] 695-695: Cyclic import
Import of module datamodel_code_generator.types begins an import cycle.
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
685-685: Unused noqa directive (non-enabled: PLR0912, PLR0915)
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: CodeQL
- GitHub Check: benchmarks
- GitHub Check: py312-isort7 on Ubuntu
- GitHub Check: 3.12 on Windows
- GitHub Check: py312-isort5 on Ubuntu
- GitHub Check: py312-black24 on Ubuntu
- GitHub Check: 3.11 on Ubuntu
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: Analyze (python)
🔇 Additional comments (10)
src/datamodel_code_generator/_types/generate_config_dict.py (1)
55-55: LGTM: Alias type broadened to support multiple values.The type change from
Mapping[str, str] | NonetoMapping[str, str | list[str]] | Noneis backward compatible and aligns with the PR's objective to support multiple aliases per field (useful for Pydantic v2 AliasChoices).src/datamodel_code_generator/__init__.py (1)
472-472: LGTM: Public API updated to support multiple aliases.The parameter type change is consistent with the broader alias handling updates across the codebase and maintains backward compatibility.
src/datamodel_code_generator/_types/parser_config_dict.py (1)
49-49: LGTM: Config type updated for multiple alias support.The type widening is consistent with the broader changes and maintains backward compatibility.
src/datamodel_code_generator/reference.py (1)
228-228: LGTM: Constructor signatures updated for multiple alias support.The type changes to
Mapping[str, str | list[str]] | Nonein bothFieldNameResolver.__init__andModelResolver.__init__are consistent with the broader alias handling updates across the codebase.Also applies to: 529-529
src/datamodel_code_generator/parser/graphql.py (1)
110-124: Approve config-driven initialization pattern with note on merge semantics.The config initialization and merging logic (lines 110-124) correctly implements:
- Config creation from options when config is None
- Option merging when both are provided (options take precedence)
- Default datetime class for GraphQL
Note: When both
configandoptionsare provided,optionstake precedence viaconfig_dict.update(options). Ensure this behavior is documented and tested, especially for nested dict fields likebase_class_mapwhere shallow merging could cause unexpected behavior.Consider documenting the merge precedence in the docstring:
"""Initialize the GraphQL parser with configuration options. When both config and options are provided, individual option values take precedence over config values (shallow merge). """src/datamodel_code_generator/parser/openapi.py (1)
187-207: Approve config-driven initialization pattern.The config initialization logic correctly implements:
- Config creation from options when config is None
- Option merging when both are provided (options take precedence)
- Default
DatetimeClassType.Awaredatetimefor OpenAPI (different from GraphQL'sDatetime)- Initialization of OpenAPI-specific fields from config
The implementation is consistent with the pattern used in
graphql.py. Same note applies: when bothconfigandoptionsare provided, shallow merge semantics could affect nested dict fields.Consider adding the same merge precedence documentation mentioned in the
graphql.pyreview.src/datamodel_code_generator/parser/jsonschema.py (2)
83-86: LGTM!Clean addition of type-only imports under the
TYPE_CHECKINGblock, supporting the new config-driven initialization pattern.
659-665: Config-driven default fortarget_datetime_classlooks correct.The logic properly applies the default
DatetimeClassType.Awaredatetimeonly whenconfig.target_datetime_class is None, which addresses the previous review concern about silently overriding config values.src/datamodel_code_generator/parser/base.py (2)
697-713: LGTM! Clean config-driven initialization.The
model_rebuildcall correctly resolves forward references inParserConfigbefore validation. The config merging logic properly handles three cases:
- No config provided → create from options
- Config provided, no options → use config as-is
- Config provided with options → merge with options taking precedence
This is a solid implementation of the config-driven pattern.
715-898: Well-executed config-driven refactoring.The conversion from explicit parameters to config-driven initialization is clean and consistent. All attributes are now derived from the
ParserConfigobject with a uniform pattern. The previous issues with inconsistent boolean handling have been addressed.The special cases are handled appropriately:
extra_template_datacorrectly converts todefaultdictif needed (lines 715-717)treat_dot_as_moduleusesor Falsefor None-safe boolean conversion (line 734)ModelResolverinitialization cleanly pulls config values (lines 842-859)
| from datamodel_code_generator.config import ParserConfig | ||
| from datamodel_code_generator.model.base import DataModel, DataModelFieldBase | ||
| from datamodel_code_generator.types import DataTypeManager, StrictTypes |
There was a problem hiding this comment.
Add # noqa: PLC0415 directives to fix pipeline failures.
These runtime imports are intentionally placed inside __init__ to avoid circular import cycles. Per project conventions, lazy imports should have # noqa: PLC0415 directives to suppress the linter warning.
🔎 Proposed fix
- from datamodel_code_generator.config import ParserConfig
- from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
- from datamodel_code_generator.types import DataTypeManager, StrictTypes
+ from datamodel_code_generator.config import ParserConfig # noqa: PLC0415
+ from datamodel_code_generator.model.base import DataModel, DataModelFieldBase # noqa: PLC0415
+ from datamodel_code_generator.types import DataTypeManager, StrictTypes # noqa: PLC0415Based on learnings, defensive # noqa: PLC0415 directives should be kept on lazy imports even when Ruff might report them as unused, to prepare for potential future configuration changes.
🧰 Tools
🪛 GitHub Check: CodeQL
[notice] 693-693: Cyclic import
Import of module datamodel_code_generator.config begins an import cycle.
[notice] 694-694: Cyclic import
Import of module datamodel_code_generator.model.base begins an import cycle.
[notice] 695-695: Cyclic import
Import of module datamodel_code_generator.types begins an import cycle.
🤖 Prompt for AI Agents
In src/datamodel_code_generator/parser/base.py around lines 693 to 695, the
three runtime/lazy imports (ParserConfig, DataModel/DataModelFieldBase,
DataTypeManager/StrictTypes) need defensive linter suppression; add "# noqa:
PLC0415" to each lazy import line to silence the PLC0415 warning and prevent
future pipeline failures while keeping the imports inside the function to avoid
circular import cycles.
| from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass | ||
| from datamodel_code_generator.model.base import DataModel, DataModelFieldBase | ||
| from datamodel_code_generator.types import DataTypeManager, StrictTypes | ||
|
|
||
| # Rebuild the model to resolve forward references before validation | ||
| GraphQLParserConfigClass.model_rebuild( | ||
| _types_namespace={ | ||
| "DataModel": DataModel, | ||
| "DataModelFieldBase": DataModelFieldBase, | ||
| "DataTypeManager": DataTypeManager, | ||
| "StrictTypes": StrictTypes, | ||
| } | ||
| ) |
There was a problem hiding this comment.
Fix linting error: move imports to top-level or use TYPE_CHECKING.
The local imports at lines 96-98 violate PLC0415 (imports should be at module level). Consider:
- Move imports to the top of the file under a
TYPE_CHECKINGguard if they're only used for type checking - If imports are needed at runtime to avoid circular dependencies, suppress the linting error with a comment explaining why
The model_rebuild call (lines 101-108) appears correct for resolving forward references before validation.
🔎 Proposed fix: Use TYPE_CHECKING guard
If the imports are only for type annotations during rebuild:
+if TYPE_CHECKING:
+ from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass
+
def __init__(
self,
source: str | Path | ParseResult,
*,
config: GraphQLParserConfig | None = None,
**options: Any,
) -> None:
"""Initialize the GraphQL parser with configuration options."""
- from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass
from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
from datamodel_code_generator.types import DataTypeManager, StrictTypesOtherwise, add a suppression comment:
+ # Import here to avoid circular dependency # noqa: PLC0415
from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass | |
| from datamodel_code_generator.model.base import DataModel, DataModelFieldBase | |
| from datamodel_code_generator.types import DataTypeManager, StrictTypes | |
| # Rebuild the model to resolve forward references before validation | |
| GraphQLParserConfigClass.model_rebuild( | |
| _types_namespace={ | |
| "DataModel": DataModel, | |
| "DataModelFieldBase": DataModelFieldBase, | |
| "DataTypeManager": DataTypeManager, | |
| "StrictTypes": StrictTypes, | |
| } | |
| ) | |
| # noqa: PLC0415 | |
| from datamodel_code_generator.config import GraphQLParserConfig as GraphQLParserConfigClass | |
| # noqa: PLC0415 | |
| from datamodel_code_generator.model.base import DataModel, DataModelFieldBase | |
| # noqa: PLC0415 | |
| from datamodel_code_generator.types import DataTypeManager, StrictTypes | |
| # Rebuild the model to resolve forward references before validation | |
| GraphQLParserConfigClass.model_rebuild( | |
| _types_namespace={ | |
| "DataModel": DataModel, | |
| "DataModelFieldBase": DataModelFieldBase, | |
| "DataTypeManager": DataTypeManager, | |
| "StrictTypes": StrictTypes, | |
| } | |
| ) |
🧰 Tools
🪛 GitHub Actions: Lint
[error] 96-98: PL C0415 import should be at the top-level of a file
🤖 Prompt for AI Agents
In src/datamodel_code_generator/parser/graphql.py around lines 96 to 108, local
imports of GraphQLParserConfigClass, DataModel, DataModelFieldBase,
DataTypeManager, and StrictTypes cause PLC0415; move these imports to the module
top and wrap them in a TYPE_CHECKING guard if they are only used for typing
(from typing import TYPE_CHECKING) so they don't execute at runtime, or if they
must remain local to avoid circular imports keep them local but add a comment
explaining the circular-import reason and suppress the lint error with # noqa:
PLC0415.
| from datamodel_code_generator.config import OpenAPIParserConfig as OpenAPIParserConfigClass | ||
| from datamodel_code_generator.model.base import DataModel, DataModelFieldBase | ||
| from datamodel_code_generator.types import DataTypeManager, StrictTypes | ||
|
|
||
| # Rebuild the model to resolve forward references before validation | ||
| OpenAPIParserConfigClass.model_rebuild( | ||
| _types_namespace={ | ||
| "DataModel": DataModel, | ||
| "DataModelFieldBase": DataModelFieldBase, | ||
| "DataTypeManager": DataTypeManager, | ||
| "StrictTypes": StrictTypes, | ||
| } | ||
| ) |
There was a problem hiding this comment.
Fix linting error: move imports to top-level or use TYPE_CHECKING.
The local imports at lines 173-175 violate PLC0415 (imports should be at module level), same issue as in graphql.py. Consider:
- Move imports to the top under a
TYPE_CHECKINGguard if only used for type checking - Add a suppression comment if needed at runtime to avoid circular dependencies
The model_rebuild call (lines 178-185) appears correct for resolving forward references.
🔎 Proposed fix: Use TYPE_CHECKING guard or add suppression
If imports are only for type annotations:
+if TYPE_CHECKING:
+ from datamodel_code_generator.config import OpenAPIParserConfig as OpenAPIParserConfigClass
+
def __init__(
self,
source: str | Path | list[Path] | ParseResult,
*,
config: OpenAPIParserConfig | None = None,
**options: Any,
) -> None:
"""Initialize the OpenAPI parser with configuration options."""
- from datamodel_code_generator.config import OpenAPIParserConfig as OpenAPIParserConfigClass
from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
from datamodel_code_generator.types import DataTypeManager, StrictTypesOtherwise:
+ # Import here to avoid circular dependency # noqa: PLC0415
from datamodel_code_generator.config import OpenAPIParserConfig as OpenAPIParserConfigClassCommittable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 GitHub Actions: Lint
[error] 173-175: PL C0415 import should be at the top-level of a file
[error] 173-175: PLC0415 import should be at the top-level of a file
🤖 Prompt for AI Agents
In src/datamodel_code_generator/parser/openapi.py around lines 173 to 185, local
imports of OpenAPIParserConfigClass, DataModel, DataModelFieldBase,
DataTypeManager and StrictTypes trigger PLC0415; move these imports to the
module top and guard them with typing.TYPE_CHECKING (from typing import
TYPE_CHECKING) if they are only used for type checking, e.g. import inside a
TYPE_CHECKING block, or if they must remain runtime imports keep them at top and
add a linter suppression comment for PLC0415 to avoid the violation and prevent
circular import issues; leave the model_rebuild call as-is.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (5)
src/datamodel_code_generator/parser/openapi.py (1)
173-177: Keep# noqa: PLC0415on lazy imports despite RUF100The local imports of
OpenAPIParserConfigClassandmodel_dumpin__init__are deliberate lazy imports guarded with# noqa: PLC0415. Even though Ruff flags these as “unusednoqa” (RUF100) today, the directive is useful if PLC0415 is enabled in future, and matches the project’s established pattern for lazy imports. I’d keep them as-is and ignore the RUF100 hint.src/datamodel_code_generator/parser/graphql.py (1)
96-99: Retain lazy-import# noqa: PLC0415even with RUF100As with
openapi.py, these imports are intentionally local to__init__and annotated with# noqa: PLC0415to tolerate an import-at-top-level rule if it’s enabled later. I’d ignore Ruff’s RUF100 suggestion here and keep the directives.src/datamodel_code_generator/config.py (1)
212-217: Keep lazy-import# noqa: PLC0415directives despite RUF100The imports of
DataModel,DataModelFieldBase,DataTypeManager, andStrictTypesinsidefrom_optionsare intentionally deferred to avoid import cycles betweenconfig,model.base, andtypes. The# noqa: PLC0415comments are defensive for when PLC0415 is enabled, and should be kept even though Ruff currently marks them as unused (RUF100).src/datamodel_code_generator/parser/jsonschema.py (2)
83-87: JsonSchemaParser now correctly delegates all options via ParserConfigThe new
__init__signature and body:
- Build/merge a
ParserConfigviaParserConfigClass.from_options(withoptionsoverriding any existing config values).- Only apply the
DatetimeClassType.Awaredatetimedefault whenconfig.target_datetime_classis stillNone.- Call
super().__init__(source=source, config=config)so the baseParserhandles all common wiring.This fixes the earlier issue where a local
target_datetime_classdefault could override a value set inParserConfig, and aligns JsonSchemaParser with the same config-driven pattern as the other parsers.Also applies to: 627-651
635-636: RUF100 on# noqa: PLC0415can be ignored hereThe local imports of
ParserConfigClassandmodel_dumpinJsonSchemaParser.__init__are intentional lazy imports with# noqa: PLC0415, mirroring the approach elsewhere to avoid potential circular imports and future PLC0415 issues. I’d keep these directives despite Ruff’s unused-noqahint.
🧹 Nitpick comments (5)
src/datamodel_code_generator/parser/openapi.py (1)
192-195: Consider keeping a backward-compatible alias foropen_api_scopes
OpenAPIParsernow exposesself.open_api_scopes(note the extra underscore) instead of something likeopenapi_scopes. If external callers were reading a previous attribute (e.g.parser.openapi_scopes), this change could be a silent breaking change. Consider adding an alias assignment or property (e.g.self.openapi_scopes = self.open_api_scopes) to ease transition.Also applies to: 685-704
tests/main/test_public_api_signature_baseline.py (1)
233-315: Union-string normalization is correct but subtle; consider adding direct testsThe new
_normalize_union_strand_split_generic_argsfunctions correctly handle:
- Nested generics like
Mapping[str, list[int | None]]- Top-level unions like
A | B | C- ForwardRef/string annotations where unions appear inside generics
by tracking bracket depth and recursively normalizing inner segments before sorting top-level union parts. Given the string-wrangling is non-trivial, it might be worth adding a small set of focused tests (e.g. parametrized over representative type strings) to catch regressions independent of the config/TypedDict comparison tests.
src/datamodel_code_generator/config.py (1)
208-237:ParserConfig.from_optionscorrectly handles v2/v1 differences, but repeats rebuildThe
from_optionsclassmethod:
- For v2: lazily imports
DataModel,DataModelFieldBase,DataTypeManager,StrictTypes, callscls.model_rebuild(_types_namespace=...), then validates options viamodel_validate.- For v1: synthesizes a defaults dict from
cls.__fields__, overlaysoptions, and usesconstruct()to bypass forward-ref resolution.This should give the right behavior for both versions and support subclasses like
OpenAPIParserConfig/GraphQLParserConfigviaSelf. The only minor concern is thatmodel_rebuildwill be invoked on every call in v2; if this becomes hot, you might later consider a small guard (e.g., a class-level flag) to avoid redundant rebuilds, but it’s not critical right now.src/datamodel_code_generator/parser/base.py (2)
71-71: MoveDataTypeManagerimport toTYPE_CHECKINGblock to avoid circular imports.
DataTypeManageris only used as a type annotation (line 707) and isn't needed at runtime. Moving it to theTYPE_CHECKINGblock will prevent potential circular import issues.🔎 Proposed refactor
-from datamodel_code_generator.types import DataType, DataTypeManager +from datamodel_code_generator.types import DataTypeAnd in the
TYPE_CHECKINGblock:if TYPE_CHECKING: from collections.abc import Iterable, Iterator, Sequence from datamodel_code_generator.config import ParserConfig + from datamodel_code_generator.types import DataTypeManager
682-682: Remove unusednoqadirective.The
noqadirective forPLR0912, PLR0915is no longer needed as these complexity rules are not enabled in your linting configuration.🔎 Proposed fix
- def __init__( # noqa: PLR0912, PLR0915 + def __init__( self, source: str | Path | list[Path] | ParseResult | dict[str, YamlValue], *,
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/datamodel_code_generator/config.pysrc/datamodel_code_generator/parser/base.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/jsonschema.pysrc/datamodel_code_generator/parser/openapi.pytests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:23:08.506Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:23:08.506Z
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:
tests/main/test_public_api_signature_baseline.pysrc/datamodel_code_generator/parser/openapi.pysrc/datamodel_code_generator/parser/base.py
📚 Learning: 2025-12-25T09:22:22.481Z
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:22.481Z
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/parser/openapi.pysrc/datamodel_code_generator/parser/graphql.pysrc/datamodel_code_generator/parser/base.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/parser/base.py
🧬 Code graph analysis (4)
src/datamodel_code_generator/parser/openapi.py (3)
src/datamodel_code_generator/util.py (1)
model_dump(254-258)src/datamodel_code_generator/config.py (2)
OpenAPIParserConfig(351-356)from_options(209-237)src/datamodel_code_generator/enums.py (1)
OpenAPIScope(70-78)
src/datamodel_code_generator/config.py (4)
src/datamodel_code_generator/util.py (1)
is_pydantic_v2(52-57)src/datamodel_code_generator/model/base.py (2)
DataModel(621-930)DataModelFieldBase(151-469)src/datamodel_code_generator/enums.py (2)
StrictTypes(213-220)OpenAPIScope(70-78)src/datamodel_code_generator/parser/jsonschema.py (1)
model_rebuild(215-217)
src/datamodel_code_generator/parser/graphql.py (3)
src/datamodel_code_generator/parser/__init__.py (1)
LiteralType(20-25)src/datamodel_code_generator/parser/base.py (1)
Parser(675-3078)src/datamodel_code_generator/config.py (2)
GraphQLParserConfig(359-363)from_options(209-237)
src/datamodel_code_generator/parser/jsonschema.py (3)
src/datamodel_code_generator/config.py (2)
ParserConfig(195-348)from_options(209-237)src/datamodel_code_generator/util.py (1)
model_dump(254-258)src/datamodel_code_generator/format.py (1)
DatetimeClassType(50-57)
🪛 Ruff (0.14.10)
tests/main/test_public_api_signature_baseline.py
233-233: Unused noqa directive (non-enabled: PLR0912)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/openapi.py
173-173: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
176-176: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/config.py
212-212: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
216-216: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/graphql.py
96-96: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
99-99: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/jsonschema.py
635-635: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
636-636: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
src/datamodel_code_generator/parser/base.py
682-682: Unused noqa directive (non-enabled: PLR0912, PLR0915)
Remove unused noqa directive
(RUF100)
690-690: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
691-691: 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: 3.11 on Windows
- GitHub Check: py312-black22 on Ubuntu
- GitHub Check: py312-isort7 on Ubuntu
- GitHub Check: py312-black23 on Ubuntu
- GitHub Check: py312-isort6 on Ubuntu
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.13 on Ubuntu
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: benchmarks
- GitHub Check: Analyze (python)
🔇 Additional comments (9)
src/datamodel_code_generator/parser/openapi.py (1)
165-194: Config-driven__init__wiring and datetime default look correctThe config resolution logic (
config is None, merge withoptions, then filltarget_datetime_classonly when stillNone) keeps options precedence and avoids clobbering an explicitconfig.target_datetime_class, while still defaulting toAwaredatetime. Delegating tosuper().__init__(source=source, config=config)matches the newParser.__init__contract, and derivingopen_api_scopes,include_path_parameters, anduse_status_code_in_response_namedirectly from the finalizedOpenAPIParserConfigis consistent with the rest of the PR. I don’t see functional issues here.src/datamodel_code_generator/parser/graphql.py (1)
88-120: GraphQL parser config handling and overrides are consistent with base ParserThe
GraphQLParser.__init__follows the same pattern as JsonSchema/OpenAPI: options merged intoGraphQLParserConfig, defaulttarget_datetime_classonly when missing (here toDatetime), then delegating toParser.__init__. Overridingdata_model_scalar_type,data_model_union_type, and rebindinguse_standard_collections/use_union_operatorfrom the resolved config keeps the GraphQL-specific behaviors explicit without fighting the base class. This looks sound.tests/main/test_public_api_signature_baseline.py (2)
30-49: Baseline signatures correctly track new config/aliases surfaceThe baseline imports and signatures (_BaselineParser with
config: ParserConfig | None = None, **optionsand_baseline_generate’saliases: Mapping[str, str | list[str]] | None) now mirror the updated public API (Parser.init and GenerateConfig/ParserConfig.aliases). This should keep the signature-compat tests meaningful as the config types evolve.Also applies to: 69-73
529-700: Config-based parser tests nicely cover the new initialization pathThe new
test_jsonschema_parser_with_config,test_openapi_parser_with_config, andtest_graphql_parser_with_config:
- Rebuild the relevant config models with a proper
_types_namespacefor Pydantic v2.- Instantiate each parser using a config instance instead of kwargs.
- Assert that key flags and parser-specific attributes (e.g.,
extra_template_data,open_api_scopes,data_model_scalar_type) are propagated.This gives good coverage for the core PR behavior (config-driven parser initialization) without overfitting to internal details.
src/datamodel_code_generator/config.py (3)
10-12: Aliases type expansion is consistent across config and baselinesUpdating
GenerateConfig.aliasesandParserConfig.aliasestoMapping[str, str | list[str]] | Nonematches the new baseline signature and allows multiple aliases per key in Pydantic v2 (AliasChoices-style). This keeps the configuration models and tests aligned and gives users more flexibility without breaking the existingstr-only case.Also applies to: 89-90, 255-256
195-207: Pydantic v1extra="allow"for ParserConfig is reasonable underfrom_optionsChanging the v1
Config.extrato"allow"makes sense given that the v1 path infrom_optionsusesconstruct()and may receive option dicts that include fields not explicitly modeled yet. This avoids unexpectedValidationErrors while you still control which fields are actually consumed by the parser.
351-364: OpenAPI/GraphQL-specific config classes cleanly separate parser concerns
OpenAPIParserConfigandGraphQLParserConfiginherit fromParserConfigand add only their respective specialization fields (openapi_scopes/include_path_parameters/use_status_code_in_response_nameanddata_model_scalar_type/data_model_union_type). This keeps parser-specific options structured without polluting the base config and works well with the sharedfrom_optionslogic.src/datamodel_code_generator/parser/base.py (2)
690-691: Keep# noqa: PLC0415directives despite Ruff warnings.While Ruff reports these
noqadirectives as unused, they should be retained per project conventions. These defensive directives protect against potential future Ruff configuration changes that might enable theimport-outside-top-levelrule (PLC0415).Based on learnings, defensive
# noqa: PLC0415directives should be kept on lazy imports even when Ruff reports them as unused via RUF100.
682-887: LGTM! Excellent config-driven refactoring.The conversion to config-driven initialization is well-implemented:
- Clean signature accepting
config+**optionsmaintains backward compatibility- Proper merge logic when both config and options are provided (options take precedence)
- Consistent attribute derivation from config throughout
- Lazy imports properly used to avoid circular dependencies
This refactoring significantly improves maintainability by centralizing configuration management while preserving the existing API surface through
**options.
| target_date_class=target_date_class, | ||
| treat_dot_as_module=treat_dot_as_module or False, | ||
| use_serialize_as_any=use_serialize_as_any, | ||
| from datamodel_code_generator.config import ParserConfig # noqa: PLC0415 |
Check notice
Code scanning / CodeQL
Cyclic import Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 months ago
In general, to fix a cyclic import between parser.base and config, you remove or invert the runtime import dependency so that neither module needs to import the other during execution. Type-only imports under if TYPE_CHECKING: are fine, because they don’t run at import time.
The cleanest fix here is to stop constructing ParserConfig inside Parser.__init__. Instead, require callers to pass in a proper ParserConfig instance (or at least avoid referencing ParserConfig in this method) so that parser.base no longer imports datamodel_code_generator.config at runtime. That breaks the cycle while preserving functionality by delegating configuration construction to the caller or by only using duck-typed attributes. We already have a TYPE_CHECKING import of ParserConfig (for type hints), so we can safely remove the runtime import and the call to ParserConfig.from_options, and treat config as an object with the required attributes.
Concretely, in Parser.__init__:
- Remove the inline import
from datamodel_code_generator.config import ParserConfig # noqa: PLC0415. - Remove the branch that uses
ParserConfig.from_options(options)whenconfig is None. - Replace it with a simpler requirement that
configmust be provided (or at least thatconfigis notNoneat runtime) and raise an explicit error if not provided. This keeps the existing behavior for valid calls that already pass aParserConfig, and avoids any need to import theconfigmodule here. - The rest of the method can stay as-is, since it only accesses attributes on
configand doesn’t need to know its concrete class.
This way, parser.base depends only on a protocol-like interface of config (its attributes), the type hint for ParserConfig remains under if TYPE_CHECKING: for static analysis, and the runtime cycle is removed.
| @@ -686,13 +686,19 @@ | ||
| config: ParserConfig | None = None, | ||
| **options: Any, # NOTE: Subclasses handle config+options merging, so options is typically empty here | ||
| ) -> None: | ||
| """Initialize the Parser with configuration options.""" | ||
| from datamodel_code_generator.config import ParserConfig # noqa: PLC0415 | ||
| """Initialize the Parser with configuration options. | ||
|
|
||
| # Subclasses are expected to merge config+options before calling super().__init__() | ||
| # This branch handles the case when Parser is used directly (e.g., for testing) | ||
| Subclasses are expected to construct and merge configuration before calling | ||
| this initializer. The `options` argument is kept for backwards | ||
| compatibility but is not used here. | ||
| """ | ||
| if config is None: | ||
| config = ParserConfig.from_options(options) | ||
| msg = ( | ||
| "Parser.__init__ requires a non-None config instance. " | ||
| "Subclasses should construct the appropriate ParserConfig " | ||
| "before calling super().__init__." | ||
| ) | ||
| raise ValueError(msg) | ||
|
|
||
| extra_template_data: defaultdict[str, Any] | None = config.extra_template_data | ||
| if extra_template_data is not None and not isinstance(extra_template_data, defaultdict): |
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/datamodel_code_generator/parser/base.pytests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-25T09:22:22.481Z
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:22.481Z
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/parser/base.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/parser/base.py
📚 Learning: 2025-12-25T09:23:08.506Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2799
File: src/datamodel_code_generator/util.py:49-66
Timestamp: 2025-12-25T09:23:08.506Z
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/parser/base.pytests/main/test_public_api_signature_baseline.py
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/base.py
682-682: Unused noqa directive (non-enabled: PLR0912, PLR0915)
Remove unused noqa directive
(RUF100)
690-690: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
tests/main/test_public_api_signature_baseline.py
233-233: Unused noqa directive (non-enabled: PLR0912)
Remove unused noqa directive
(RUF100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: py312-isort5 on Ubuntu
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.12 on Ubuntu
- GitHub Check: py312-pydantic1 on Ubuntu
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.11 on Ubuntu
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.11 on macOS
- GitHub Check: benchmarks
- GitHub Check: Analyze (python)
🔇 Additional comments (7)
tests/main/test_public_api_signature_baseline.py (3)
64-64: LGTM! Baseline signatures correctly updated.The baseline signatures properly reflect the config-driven parser refactor:
extra_template_datanow usesdefaultdictfor auto-vivificationaliasessupports both single strings and lists- Parser constructor accepts
configand**optionsAlso applies to: 69-69, 182-183
572-701: Excellent test coverage for config-driven parser initialization.These tests comprehensively verify that parser subclasses correctly accept and apply
ParserConfigvariants:
- JsonSchemaParser with ParserConfig
- OpenAPIParser with OpenAPIParserConfig
- GraphQLParser with GraphQLParserConfig
The proper use of
model_rebuildwith type namespace ensures tests work correctly with Pydantic v2.
703-865: Strong validation of config+options merge semantics.These tests ensure the critical behavior where options override config values:
- Config sets baseline values
- Options parameters take precedence
extra_template_dataautomatically converts fromdicttodefaultdict- Defaultdict behavior works correctly (returns empty dict for missing keys)
This validates backward compatibility while supporting the new config-driven API.
src/datamodel_code_generator/parser/base.py (4)
74-77: LGTM! Proper circular import avoidance.The TYPE_CHECKING import of
ParserConfigcombined with runtime import at line 690 correctly avoids circular import issues while maintaining type safety.
690-690: Note: Thenoqa: PLC0415directive is intentional.Despite Ruff's RUF100 warning, this defensive
# noqa: PLC0415should be retained. Based on learnings, defensive noqa directives on lazy imports are kept even when reported as unused, to prepare for potential future Ruff configuration changes that might enable the import-outside-toplevel rule.
690-699: Well-designed config initialization logic.The initialization correctly handles multiple scenarios:
- Runtime import breaks circular dependencies
- Falls back to creating config from options when Parser is used directly
- Converts regular
dicttodefaultdictfor backward compatibility- Subclasses handle config+options merging before calling super()
This provides a clean migration path while maintaining backward compatibility.
701-883: Comprehensive config-driven initialization.The attribute initialization is well-structured:
- All ~90 parser attributes correctly initialized from config
DataTypeManagerinstantiated with appropriate config parameters- Imports properly handle
use_exact_importsandadditional_importsModelResolverreceives all necessary config options- Generic base class and template data configurations applied correctly
The migration from explicit keyword parameters to config-driven initialization is complete and correct.
| """ | ||
|
|
||
| def __init__( # noqa: PLR0912, PLR0913, PLR0915 | ||
| def __init__( # noqa: PLR0912, PLR0915 |
There was a problem hiding this comment.
Remove unused noqa directives.
The noqa directives for PLR0912 (too-many-branches) and PLR0915 (too-many-statements) are unnecessary as these rules are not enabled in your linting configuration. This was previously marked as addressed but the directives remain.
🔎 Proposed fix
- def __init__( # noqa: PLR0912, PLR0915
+ def __init__(
self,
source: str | Path | list[Path] | ParseResult | dict[str, YamlValue],🧰 Tools
🪛 Ruff (0.14.10)
682-682: Unused noqa directive (non-enabled: PLR0912, PLR0915)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In src/datamodel_code_generator/parser/base.py around line 682, the __init__
definition contains an unused " # noqa: PLR0912, PLR0915" directive; remove the
noqa comment from the def __init__ line so the signature reads normally without
the trailing noqa, and commit the change (no other code changes required).
| parts = [p.strip() for p in type_str.split(" | ")] | ||
| return " | ".join(sorted(parts)) | ||
| return type_str | ||
| def _normalize_union_str(type_str: str) -> str: # noqa: PLR0912 |
There was a problem hiding this comment.
Remove unused noqa directive.
The noqa: PLR0912 directive is unnecessary as the PLR0912 rule (too-many-branches) is not enabled in your linting configuration.
🔎 Proposed fix
-def _normalize_union_str(type_str: str) -> str: # noqa: PLR0912
+def _normalize_union_str(type_str: str) -> str:
"""Normalize a union type string by sorting its components recursively.🧰 Tools
🪛 Ruff (0.14.10)
233-233: Unused noqa directive (non-enabled: PLR0912)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In tests/main/test_public_api_signature_baseline.py around line 233, the
function definition contains an unnecessary noqa directive ("# noqa: PLR0912");
remove the unused directive from the function signature so it becomes a normal
def _normalize_union_str(type_str: str) -> str: and run tests/lint to confirm no
warnings remain.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/datamodel_code_generator/config.py (1)
251-251: Verify backward compatibility of thealiasestype extension.Same type extension as
GenerateConfig.aliases(line 89). This verification comment applies to both fields.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/datamodel_code_generator/config.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/config.py (3)
src/datamodel_code_generator/util.py (1)
is_pydantic_v2(52-57)src/datamodel_code_generator/enums.py (1)
StrictTypes(213-220)src/datamodel_code_generator/parser/jsonschema.py (1)
model_rebuild(215-217)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/config.py
212-212: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
216-216: 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). (10)
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.13 on macOS
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.12 on macOS
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: benchmarks
- GitHub Check: Analyze (python)
🔇 Additional comments (3)
src/datamodel_code_generator/config.py (3)
11-11: LGTM!The
Selfimport is correctly used for the self-referential return type in thefrom_optionsclassmethod.
347-353: LGTM!The
OpenAPIParserConfigclass is well-structured with appropriate OpenAPI-specific fields. The inheritance fromParserConfigfollows the config-driven pattern described in the PR.
355-360: LGTM!The
GraphQLParserConfigclass follows the same pattern asOpenAPIParserConfigwith appropriate GraphQL-specific fields for data model types.
| snake_case_field: bool = False | ||
| strip_default_none: bool = False | ||
| aliases: Mapping[str, str] | None = None | ||
| aliases: Mapping[str, str | list[str]] | None = None |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find all usages of the aliases field and its access patterns
rg -nP --type=py 'aliases' -C3 | head -200Repository: koxudaxi/datamodel-code-generator
Length of output: 17256
🏁 Script executed:
# Check the watch.py function signature and how it uses aliases
cat -n src/datamodel_code_generator/watch.py | head -60Repository: koxudaxi/datamodel-code-generator
Length of output: 2632
🏁 Script executed:
# Check the generate function signature that watch.py calls
rg -n 'def generate' src/datamodel_code_generator/__init__.py -A 20 | head -80Repository: koxudaxi/datamodel-code-generator
Length of output: 1141
Fix type signature mismatch in watch.py for aliases parameter.
The watch_and_regenerate function declares aliases: dict[str, str] | None (line 26) but should be dict[str, str | list[str]] | None to match the updated signature in generate() and the configuration classes. The type must support both str and list[str] values to maintain consistency with the extended type in GenerateConfig and ParserConfig.
🤖 Prompt for AI Agents
In src/datamodel_code_generator/config.py around line 89 and in
src/datamodel_code_generator/watch.py around line 26, the type for aliases must
allow both string and list[string]; update the watch.py parameter and any
related annotations from dict[str, str] | None to dict[str, str | list[str]] |
None (or the equivalent Mapping/typing form used across the project) so it
matches GenerateConfig/ParserConfig; ensure any usages or type checks that
assume a simple str are adjusted to handle list[str] as well and update imports
(typing.Mapping or list union) if required.
| """Pydantic v1 model config.""" | ||
|
|
||
| extra = "forbid" | ||
| extra = "allow" |
There was a problem hiding this comment.
Critical: Inconsistent extra field handling between Pydantic v1 and v2.
Pydantic v2 config (line 199) has extra="forbid", but this change sets extra="allow" for v1 (line 205). This creates version-dependent validation behavior where:
- v1 silently accepts extra/invalid fields
- v2 rejects them with a validation error
This inconsistency undermines cross-version compatibility and could mask typos or incorrect field names when running on v1.
🔎 Proposed fix
- extra = "allow"
+ extra = "forbid"If extra fields are needed for the config-merging pattern described in the PR, consider handling them explicitly in from_options rather than changing the model's validation behavior.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| extra = "allow" | |
| extra = "forbid" |
🤖 Prompt for AI Agents
In src/datamodel_code_generator/config.py around line 205, the change sets
Pydantic v1 model config extra="allow" which conflicts with the v2 config
extra="forbid" at ~line 199 and creates version-dependent behavior; revert the
v1 config to extra="forbid" to match v2, and if the codebase needs to accept or
merge extra fields implement explicit handling inside the classmethod
from_options (collect/populate allowed extras there) rather than changing the
model's validation behavior so both Pydantic versions reject unknown fields by
default.
| from datamodel_code_generator.model.base import ( # noqa: PLC0415 | ||
| DataModel, | ||
| DataModelFieldBase, | ||
| ) | ||
| from datamodel_code_generator.types import DataTypeManager, StrictTypes # noqa: PLC0415 |
There was a problem hiding this comment.
Remove unused noqa directives.
The noqa: PLC0415 directives on lines 212 and 216 are not needed, as indicated by static analysis.
🔎 Proposed fix
- from datamodel_code_generator.model.base import ( # noqa: PLC0415
+ from datamodel_code_generator.model.base import (
DataModel,
DataModelFieldBase,
)
- from datamodel_code_generator.types import DataTypeManager, StrictTypes # noqa: PLC0415
+ from datamodel_code_generator.types import DataTypeManager, StrictTypes📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| from datamodel_code_generator.model.base import ( # noqa: PLC0415 | |
| DataModel, | |
| DataModelFieldBase, | |
| ) | |
| from datamodel_code_generator.types import DataTypeManager, StrictTypes # noqa: PLC0415 | |
| from datamodel_code_generator.model.base import ( | |
| DataModel, | |
| DataModelFieldBase, | |
| ) | |
| from datamodel_code_generator.types import DataTypeManager, StrictTypes |
🧰 Tools
🪛 Ruff (0.14.10)
212-212: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
216-216: Unused noqa directive (non-enabled: PLC0415)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In src/datamodel_code_generator/config.py around lines 212 to 216, the trailing
"noqa: PLC0415" directives on the two import lines are unnecessary; remove the "
# noqa: PLC0415" suffixes from the import statements so the imports remain the
same but without the unused noqa directives, keeping the lines otherwise
unchanged.
| # For Pydantic v1, use construct() to skip validation (forward refs not resolved) | ||
| defaults: dict[str, Any] = {} | ||
| for field_name, field in cls.__fields__.items(): # type: ignore[attr-defined] | ||
| # Note: ParserConfig fields don't use default_factory, so we only handle static defaults | ||
| defaults[field_name] = field.default | ||
| defaults.update(options) | ||
| return cls.construct(**defaults) # type: ignore[return-value] |
There was a problem hiding this comment.
Pydantic v1 path bypasses validation entirely using construct().
The Pydantic v1 code path uses construct() to skip validation due to unresolved forward references. However, this bypasses ALL validation, not just forward-ref resolution, which could allow invalid or inconsistent configuration objects to be created.
Consider alternative approaches:
- Use
parse_obj()ormodel_validate()equivalents that perform validation - Pre-resolve the required types before validation (similar to the v2 approach)
- Document why validation must be skipped and the risks involved
🤖 Prompt for AI Agents
In src/datamodel_code_generator/config.py around lines 227 to 233, the Pydantic
v1 path currently uses cls.construct(...) which skips all validation; instead,
call cls.update_forward_refs() to resolve forward references and then
instantiate with validation (e.g., use cls.parse_obj(defaults) or
cls(**defaults)) so validation runs; also catch and re-raise or log
pydantic.ValidationError with a clear message to preserve existing error
behavior.
Summary by CodeRabbit
New Features
Refactor
Tests
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.