Skip to content

Refactor parser base post-processing for DRY and type-safe implementation#2730

Merged
koxudaxi merged 1 commit intomainfrom
refactor/parser-base-post-processing
Dec 22, 2025
Merged

Refactor parser base post-processing for DRY and type-safe implementation#2730
koxudaxi merged 1 commit intomainfrom
refactor/parser-base-post-processing

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 22, 2025

Summary by CodeRabbit

  • New Features

    • Broader discriminator support across more model backends.
    • Field renaming and wrapped-default handling enabled for newer model variants.
    • Keyword-only argument support added for dataclasses and certain models.
    • Added traversal capability for data-type trees to improve tooling/analysis.
  • Refactor

    • Parsing pipeline reorganized into clearer stages for reliability and extensibility.
    • Import management improved to more aggressively remove unused imports.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 22, 2025

Walkthrough

Adds import utility methods for alias resolution and unused-import removal, introduces model capability flags across several data-model implementations, refactors the parser into a module-based pipeline with ModuleContext/ParseConfig, and adds a recursive DataType.walk visitor with cycle protection.

Changes

Cohort / File(s) Change Summary
Model Capability Flags
src/datamodel_code_generator/model/base.py, src/datamodel_code_generator/model/dataclass.py, src/datamodel_code_generator/model/msgspec.py, src/datamodel_code_generator/model/pydantic/base_model.py, src/datamodel_code_generator/model/pydantic_v2/base_model.py
Added class-level feature flags (SUPPORTS_DISCRIMINATOR, SUPPORTS_FIELD_RENAMING, SUPPORTS_WRAPPED_DEFAULT, SUPPORTS_KW_ONLY) on DataModel and concrete model classes; specific flags enabled per backend (dataclass, msgspec, pydantic v1/v2)
Import Utilities
src/datamodel_code_generator/imports.py
Added `get_effective_name(from_: str
Parser Refactoring
src/datamodel_code_generator/parser/base.py
Major restructure: added type aliases (ModulePath, ModuleModels, ForwarderMap), ModuleContext and ParseConfig NamedTuples; new helpers (_build_module_structure, _process_single_module, _finalize_modules, _generate_module_output, _generate_empty_init_exports, _prepare_parse_config); parse pipeline now builds module structure, processes modules into contexts, finalizes them, and renders outputs; many internal methods updated to consult model capability flags
Type System Enhancement
src/datamodel_code_generator/types.py
Added `DataType.walk(visitor: Callable[[DataType], None], visited: set[int]

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI as CLI / Caller
  participant Parser as Parser
  participant Builder as _build_module_structure
  participant Processor as _process_single_module
  participant Finalizer as _finalize_modules
  participant Renderer as _generate_module_output
  participant FS as FileSystem

  CLI->>Parser: parse(input, config)
  Parser->>Parser: _prepare_parse_config(config)
  Parser->>Builder: _build_module_structure(parse_config)
  Builder-->>Parser: ModuleModels, internal map, ForwarderMap
  Parser->>Processor: for each module -> _process_single_module(context)
  Processor-->>Parser: ModuleContext (per-module)
  Parser->>Finalizer: _finalize_modules(list(ModuleContext))
  Finalizer-->>Parser: finalized contexts (imports cleaned, forwarders added)
  Parser->>Renderer: _generate_module_output(ModuleContext)
  Renderer-->>FS: write module files / __init__ exports
  FS-->>CLI: output paths
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus review on parser refactor: follow dataflow across _build_module_structure, _process_single_module, _finalize_modules, and output generation.
  • Verify capability flags used consistently where gating behavior changed.
  • Inspect imports.remove_unused for edge cases with alias/reference path counters.
  • Validate DataType.walk to ensure no infinite recursion and correct visitation order.

🐇 New flags, a cleaner pipeline I sing,
Imports trimmed and walker on the wing.
Modules built, then processed with care,
Files emerge from contexts laid bare.
Hop, code, hop — a rabbit’s tiny cheer!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.86% 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 accurately describes the main refactoring effort: introducing type-safe abstractions (ModuleContext, ParseConfig, ForwarderMap) and extracting post-processing logic into dedicated methods (__apply_generic_base_class, _finalize_modules, _generate_module_output) to improve code organization and reduce duplication.
✨ 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/parser-base-post-processing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 22, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2730   +/-   ##
=======================================
  Coverage   99.35%   99.36%           
=======================================
  Files          83       83           
  Lines       12004    12062   +58     
  Branches     1452     1456    +4     
=======================================
+ Hits        11927    11985   +58     
  Misses         45       45           
  Partials       32       32           
Flag Coverage Δ
unittests 99.36% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 22, 2025

CodSpeed Performance Report

Merging #2730 will not alter performance

Comparing refactor/parser-base-post-processing (661dc23) with main (ae11c41)

Summary

✅ 70 untouched
⏩ 10 skipped1

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@koxudaxi koxudaxi force-pushed the refactor/parser-base-post-processing branch from 77b7529 to 661dc23 Compare December 22, 2025 07:51
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

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/base.py (1)

2592-2657: Potential stale mapping for unused_models after circular-module resolution

_build_module_structure builds model_to_module_models before calling __resolve_circular_imports, which can move models into synthetic _internal modules and replace the per-module model lists. Later, _finalize_modules uses model_to_module_models to locate and remove unused_models (from __collapse_root_models) and to update imports via module_to_import. For models that have been relocated into an _internal module, this mapping will still point at the original module and its pre-resolution list, so:

  • The models.remove(unused_model) call can operate on a list that is no longer the one used by any ModuleContext, leaving the unused model in the actual output.
  • Imports for the real module containing the unused model (e.g., the _internal module) will not be cleaned up.

This is an edge case (it requires both cross-module SCCs and collapsible root models), but it’s a real behavioral divergence.

Suggested refactor to bind removals to the final module structure

One approach is to derive the “model → context” mapping from contexts instead of carrying model_to_module_models through:

-    def _finalize_modules(
-        self,
-        contexts: list[ModuleContext],
-        unused_models: list[DataModel],
-        model_to_module_models: dict[DataModel, tuple[ModulePath, list[DataModel]]],
-        module_to_import: dict[ModulePath, Imports],
-    ) -> None:
+    def _finalize_modules(
+        self,
+        contexts: list[ModuleContext],
+        unused_models: list[DataModel],
+    ) -> None:
         """Finalize module processing: apply generic base class and remove unused imports."""
         self.__apply_generic_base_class(contexts)
 
-        for ctx in contexts:
-            for model in ctx.models:
-                ctx.imports.append(model.imports)
-
-        for unused_model in unused_models:
-            module, models = model_to_module_models[unused_model]
-            if unused_model in models:
-                imports = module_to_import[module]
-                imports.remove(unused_model.imports)
-                models.remove(unused_model)
+        # Bind each model to its final module context.
+        model_to_context: dict[DataModel, ModuleContext] = {}
+        for ctx in contexts:
+            for model in ctx.models:
+                model_to_context[model] = ctx
+                ctx.imports.append(model.imports)
+
+        # Drop models that became unused after root-model collapsing, etc.
+        for unused_model in unused_models:
+            ctx = model_to_context.get(unused_model)
+            if not ctx:
+                continue
+            ctx.imports.remove(unused_model.imports)
+            try:
+                ctx.models.remove(unused_model)
+            except ValueError:
+                # Model already removed; ignore.
+                pass

and update the call site in parse() accordingly:

-        self._finalize_modules(contexts, unused_models, model_to_module_models, module_to_import)
+        self._finalize_modules(contexts, unused_models)

This ties removals to the post–__resolve_circular_imports module layout and ensures unused models really disappear from both code and import sets.

Also applies to: 2721-2745

🧹 Nitpick comments (3)
src/datamodel_code_generator/imports.py (1)

171-197: Alias-aware unused-import pruning looks correct for current usage

get_effective_name plus remove_unused correctly consider both the alias and original imported name, which matches how _collect_used_names_from_models builds used_names (based on aliases and simple identifiers). The loop that repeatedly calls remove until the counter reaches zero respects the reference counting in Imports. For typical module sizes this O(n²) behavior over reference_paths is acceptable; you can revisit it if modules ever accumulate hundreds of distinct imports.

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

2547-2590: ParseConfig helper looks good; consider cleaning up stale noqa directives

The new _prepare_parse_config cleanly centralizes computation of use_deferred_annotations, global IMPORT_ANNOTATIONS, and the optional CodeFormatter. The subsequent parse() refactor that delegates to this helper improves readability.

Static analysis (RUF100) points out that several # noqa directives on these definitions (PLR0913, PLR0914, PLR0917, FBT001, FBT002) are now unused under the current Ruff configuration. If you don’t plan to enable those checks, you can drop the corresponding # noqa comments to keep the file tidy.

Also applies to: 2843-2852


2547-2552: Ruff RUF100: several noqa comments can likely be dropped

Ruff reports unused # noqa directives for PLR0913, PLR0914, PLR0917, FBT001, and FBT002 on parse, _prepare_parse_config, _process_single_module, and _generate_module_output. If your current Ruff configuration doesn’t enable these rules, you can safely remove the corresponding # noqa comments; otherwise consider enabling the checks so the directives remain meaningful.

Also applies to: 2659-2668, 2749-2755, 2843-2848

📜 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 ae11c41 and 77b7529.

📒 Files selected for processing (8)
  • src/datamodel_code_generator/imports.py
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/model/dataclass.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/model/pydantic/base_model.py
  • src/datamodel_code_generator/model/pydantic_v2/base_model.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/types.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/parser/base.py (3)
src/datamodel_code_generator/model/base.py (5)
  • DataModel (470-760)
  • imports (283-302)
  • imports (642-647)
  • path (739-741)
  • name (658-660)
src/datamodel_code_generator/imports.py (2)
  • remove (91-123)
  • remove_unused (175-196)
src/datamodel_code_generator/format.py (1)
  • format_code (272-291)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/parser/base.py

2547-2547: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2549-2549: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2550-2550: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2552-2552: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2659-2659: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2749-2749: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2843-2843: Unused noqa directive (non-enabled: PLR0913, PLR0914, PLR0917)

Remove unused noqa directive

(RUF100)


2845-2845: Unused noqa directive (non-enabled: FBT001, FBT002)

Remove unused noqa directive

(RUF100)


2846-2846: Unused noqa directive (non-enabled: FBT001, FBT002)

Remove unused noqa directive

(RUF100)


2848-2848: Unused noqa directive (non-enabled: FBT001, FBT002)

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

43-46: Dataclass capability flags are consistent with new parser gating

Exposing SUPPORTS_DISCRIMINATOR and SUPPORTS_KW_ONLY on DataClass aligns with the new DataModel defaults and the parser’s feature-gated paths (__apply_discriminator_type, __get_dataclass_inherited_info). No behavioral issues spotted.

src/datamodel_code_generator/model/msgspec.py (1)

108-117: Struct discriminator support flag fits the new feature-flag pattern

Setting SUPPORTS_DISCRIMINATOR = True on Struct matches how the parser now gates discriminator handling on DataModel.SUPPORTS_DISCRIMINATOR and avoids backend-specific isinstance checks.

src/datamodel_code_generator/model/pydantic_v2/base_model.py (1)

170-179: Pydantic v2 capability flags correctly advertise supported features

SUPPORTS_DISCRIMINATOR, SUPPORTS_FIELD_RENAMING, and SUPPORTS_WRAPPED_DEFAULT being True for the v2 BaseModel lines up with how the parser now conditionally runs discriminator logic, field renaming, and root-model default wrapping.

src/datamodel_code_generator/model/pydantic/base_model.py (1)

329-333: Pydantic v1 discriminator flag preserves existing behavior

Adding SUPPORTS_DISCRIMINATOR = True to the v1 BaseModel keeps discriminator handling enabled under the new generic flag-based checks without changing previous semantics.

src/datamodel_code_generator/types.py (1)

432-448: DataType.walk is a reasonable, cycle-safe traversal helper

The new walk method visits each node once using an id-based visited set and correctly recurses through data_types and dict_key. This is suitable for the import-usage collection in the parser without changing existing all_data_types behavior.

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

476-485: Base DataModel capability flags are a clean extensibility hook

The new SUPPORTS_* class vars (discriminator, field renaming, wrapped default, kw-only) defaulting to False provide a clear, type-level contract for parsers to query backend capabilities instead of hard-coding concrete model classes.

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

104-129: ModuleContext/ParseConfig abstractions clarify the parsing pipeline

Introducing ModulePath/ModuleModels/ForwarderMap aliases plus ModuleContext and ParseConfig makes the later helpers (_build_module_structure, _process_single_module, _generate_module_output) much easier to reason about. The fields on ModuleContext (module path, key, models, init flag, imports, resolver) are exactly what the downstream steps need.


2238-2256: Using DataType.walk in _collect_used_names_from_models improves import reachability analysis

Switching from manual iteration over all_data_types to field.data_type.walk(collect_data_type_names) ensures every reachable DataType (including nested dict keys) contributes its alias/type and reference short name to used_names, while avoiding cycles via the visited set in walk. Combined with Imports.remove_unused, this should safely prune genuinely unused imports without dropping ones referenced only from nested types.


2659-2720: Single-module processing pipeline is well-structured

_process_single_module cleanly sequences all the per-module transformations that used to be inlined in parse(): shadowed-import aliasing, required-field overrides, unique-items→set conversion, cross-module import rewrites, enum extraction, reuse, root-model collapsing, default wrapping, sort/model-order handling, discriminator application, and type-alias updates. Returning a ModuleContext encapsulates everything the later phases need (module path, models, imports, resolver) and makes the flow more testable.


2749-2815: Module output generation correctly composes imports, exports, and body

_generate_module_output:

  • Builds imports from future_imports_str, global parser imports, and per-module imports only when with_import is enabled.
  • Optionally injects __all__-driven re-export imports for __init__.py based on _collect_exports_for_init and collision strategy.
  • Emits either rendered models plus resolve-reference actions, or, when there are no models, a forwarder module based on forwarder_map.

The final optional formatting via code_formatter matches the rest of the tool’s behavior.


2816-2842: Empty-init export generation and overall parse orchestration look coherent

_generate_empty_init_exports fills in bare __init__.py files with re-exports when all_exports_scope is set, reusing the same collision-resolution logic as non-empty modules. The refactored parse() orchestrates:

  • configuration (_prepare_parse_config),
  • model sorting,
  • module-structure construction (including SCC/internal-module handling),
  • per-module processing and finalization,
  • and per-module output plus any empty-__init__ exports.

The post-processing that normalizes module keys when treat_dot_as_module is on appears unchanged from the previous logic.

Also applies to: 2898-2916


1271-1274: Feature-flag gating for discriminators, wrapped defaults, renaming, and kw-only is sound

  • __apply_discriminator_type checks isinstance(discriminator_model, DataModel) and SUPPORTS_DISCRIMINATOR, decoupling parser logic from specific backend classes.
  • __wrap_root_model_default_values is guarded by self.data_model_type.SUPPORTS_WRAPPED_DEFAULT, ensuring only backends that support WrappedDefault receive this behavior.
  • __change_field_name runs only when self.data_model_type.SUPPORTS_FIELD_RENAMING is True, leaving legacy backends unchanged.
  • __get_dataclass_inherited_info early-outs when model.SUPPORTS_KW_ONLY is false, applying the dataclass field-order fix only to kw-only-capable models.

All flags are properly defined on backend classes (False by default in base.py) and correctly set for each backend: Pydantic v2 supports all four, dataclass supports discriminators and kw-only, msgspec and Pydantic v1 support discriminators.

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/parser/base.py (1)

2547-2590: Well-executed refactoring with improved modularity.

The extraction of helper methods (_prepare_parse_config, _build_module_structure, _process_single_module, _finalize_modules, _generate_module_output, _generate_empty_init_exports) significantly improves code organization by separating concerns into focused, testable units while the main parse method now serves as a clear orchestrator.

🔎 Optional cleanup: Remove unused noqa directives

Static analysis reports several unused noqa directives that can be safely removed:

  • Line 2547: Remove # noqa: PLR0913, PLR0917
  • Line 2549: Remove # noqa: FBT001
  • Line 2550: Remove # noqa: FBT001
  • Line 2552: Remove # noqa: FBT001
  • Line 2659: Remove # noqa: PLR0913, PLR0917
  • Line 2749: Remove # noqa: PLR0913, PLR0917
  • Line 2843: Remove # noqa: PLR0913, PLR0914, PLR0917
  • Line 2845: Remove # noqa: FBT001, FBT002
  • Line 2846: Remove # noqa: FBT001, FBT002
  • Line 2848: Remove # noqa: FBT001, FBT002

These directives are no longer necessary as the refactored methods don't trigger the corresponding linting rules.

Also applies to: 2592-2657, 2659-2719, 2721-2747, 2749-2814, 2816-2841, 2843-2923

📜 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 77b7529 and 661dc23.

📒 Files selected for processing (8)
  • src/datamodel_code_generator/imports.py
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/model/dataclass.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/model/pydantic/base_model.py
  • src/datamodel_code_generator/model/pydantic_v2/base_model.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/types.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/datamodel_code_generator/model/pydantic_v2/base_model.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/imports.py
  • src/datamodel_code_generator/model/base.py
🧰 Additional context used
🧬 Code graph analysis (1)
src/datamodel_code_generator/parser/base.py (4)
src/datamodel_code_generator/model/base.py (6)
  • DataModel (470-760)
  • imports (283-302)
  • imports (642-647)
  • field (333-335)
  • path (739-741)
  • name (658-660)
src/datamodel_code_generator/imports.py (7)
  • Imports (41-196)
  • append (74-89)
  • remove (91-123)
  • remove_unused (175-196)
  • add_export (146-150)
  • dump_all (152-169)
  • extract_future (130-144)
src/datamodel_code_generator/format.py (2)
  • CodeFormatter (162-332)
  • format_code (272-291)
src/datamodel_code_generator/__init__.py (3)
  • ModuleSplitMode (303-309)
  • AllExportsScope (249-257)
  • AllExportsCollisionStrategy (260-270)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/parser/base.py

2547-2547: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2549-2549: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2550-2550: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2552-2552: Unused noqa directive (non-enabled: FBT001)

Remove unused noqa directive

(RUF100)


2659-2659: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2749-2749: Unused noqa directive (non-enabled: PLR0913, PLR0917)

Remove unused noqa directive

(RUF100)


2843-2843: Unused noqa directive (non-enabled: PLR0913, PLR0914, PLR0917)

Remove unused noqa directive

(RUF100)


2845-2845: Unused noqa directive (non-enabled: FBT001, FBT002)

Remove unused noqa directive

(RUF100)


2846-2846: Unused noqa directive (non-enabled: FBT001, FBT002)

Remove unused noqa directive

(RUF100)


2848-2848: Unused noqa directive (non-enabled: FBT001, FBT002)

Remove unused noqa directive

(RUF100)

🔇 Additional comments (7)
src/datamodel_code_generator/model/dataclass.py (1)

45-46: LGTM! Feature flags added for capability detection.

The addition of SUPPORTS_DISCRIMINATOR and SUPPORTS_KW_ONLY flags enables the parser to detect dataclass capabilities at runtime, allowing the code generation pipeline to conditionally enable discriminator handling and kw_only field support based on the target model type.

src/datamodel_code_generator/types.py (1)

432-448: LGTM! Well-implemented visitor pattern with cycle protection.

The walk method provides a clean top-down traversal of the DataType tree with proper cycle detection. The traversal order (self → data_types → dict_key) correctly implements the visitor pattern by visiting parent nodes before children, which differs intentionally from the existing all_data_types iterator that yields children before parents.

src/datamodel_code_generator/model/pydantic/base_model.py (1)

331-331: LGTM! Discriminator support flag added.

The SUPPORTS_DISCRIMINATOR flag enables the parser to detect Pydantic v1 BaseModel's discriminator capabilities, consistent with the feature flag pattern introduced across other model types.

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

104-129: LGTM! Well-designed abstractions for module processing.

The new type aliases (ModulePath, ModuleModels, ForwarderMap) and NamedTuples (ModuleContext, ParseConfig) provide clear, type-safe abstractions that improve code organization and make the refactored parsing pipeline easier to understand and maintain.


1271-1274: LGTM! Proper capability check for discriminator support.

The addition of the SUPPORTS_DISCRIMINATOR check correctly gates discriminator type application based on the model's capabilities, preventing the feature from being applied to model types that don't support it.


1767-1767: LGTM! Capability checks correctly guard feature application.

The capability flag checks at lines 1767 (SUPPORTS_WRAPPED_DEFAULT), 1843 (SUPPORTS_FIELD_RENAMING), and 1901 (SUPPORTS_KW_ONLY) properly gate their respective features based on model type capabilities, ensuring features are only applied to compatible model types.

Also applies to: 1843-1843, 1901-1901


2238-2256: LGTM! Excellent use of the new walk method.

The _collect_used_names_from_models method effectively uses the new DataType.walk method (line 2255) to collect all referenced names, replacing manual traversal with a cleaner, more maintainable visitor pattern.

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.

1 participant