Skip to content

Add --no-treat-dot-as-module option for flat output structure#2732

Merged
koxudaxi merged 9 commits intomainfrom
feature/no-treat-dot-as-module
Dec 22, 2025
Merged

Add --no-treat-dot-as-module option for flat output structure#2732
koxudaxi merged 9 commits intomainfrom
feature/no-treat-dot-as-module

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Dec 22, 2025

Fixes: #1535

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced --treat-dot-as-module CLI option with tri-state support: explicitly enable with --treat-dot-as-module, explicitly disable with --no-treat-dot-as-module, or omit for default behavior.
  • Documentation

    • Updated CLI reference guides to reflect tri-state flag semantics and usage examples.
  • Tests

    • Added test coverage for negative flag scenarios and version-style naming variations.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 22, 2025

Warning

Rate limit exceeded

@koxudaxi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 47 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 7a31127 and b7f74a7.

📒 Files selected for processing (21)
  • docs/cli-reference/quick-reference.md
  • docs/cli-reference/template-customization.md
  • tests/data/expected/main/jsonschema/treat_dot_complex_no_treat/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_no_treat/api_v1_address.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_no_treat/api_v1_user.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_no_treat/common_types_country.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_no_treat/common_types_status.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/api/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/api/v1/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/api/v1/address.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/api/v1/user.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/common/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/common/types/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/common/types/country.py
  • tests/data/expected/main/jsonschema/treat_dot_complex_treat/common/types/status.py
  • tests/data/jsonschema/treat_dot_complex/api.v1.address.json
  • tests/data/jsonschema/treat_dot_complex/api.v1.user.json
  • tests/data/jsonschema/treat_dot_complex/common.types.country.json
  • tests/data/jsonschema/treat_dot_complex/common.types.status.json
  • tests/main/jsonschema/test_main_jsonschema.py

Walkthrough

The pull request converts the treat_dot_as_module parameter from a binary boolean flag into a tri-state optional value across the codebase. The CLI flag changes from --treat-dot-as-module to --no-treat-dot-as-module, and all related type signatures are updated from bool = False to bool | None = None, with updated logic to handle the None state throughout the module name resolution and import handling pathways.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/cli-reference/index.md, docs/cli-reference/quick-reference.md, docs/cli-reference/template-customization.md
Replaced --treat-dot-as-module references with --no-treat-dot-as-module in CLI documentation and alphabetical indices; updated descriptions to reflect the negated form.
CLI Argument Configuration
src/datamodel_code_generator/arguments.py
Changed --treat-dot-as-module from store_true action to BooleanOptionalAction with default None, enabling tri-state support. Updated help text to describe nested directory creation and negation via --no-treat-dot-as-module.
CLI Option Metadata
src/datamodel_code_generator/cli_options.py
Removed --treat-dot-as-module entry and added --no-treat-dot-as-module entry in CLI_OPTION_META dictionary.
Core Public API Signatures
src/datamodel_code_generator/__init__.py, src/datamodel_code_generator/__main__.py
Updated treat_dot_as_module parameter type from bool = False to Optional[bool] = None in generate() function and Config class.
Module Name Resolution Logic
src/datamodel_code_generator/model/base.py
Updated sanitize_module_name, get_module_path, and get_module_name to accept `bool
Model Class Constructors
src/datamodel_code_generator/model/dataclass.py, src/datamodel_code_generator/model/enum.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/model/scalar.py, src/datamodel_code_generator/model/typed_dict.py, src/datamodel_code_generator/model/union.py
Updated constructor signatures to accept treat_dot_as_module: bool | None = None across all model types.
DataTypeManager Signatures
src/datamodel_code_generator/model/pydantic/types.py, src/datamodel_code_generator/model/pydantic_v2/types.py, src/datamodel_code_generator/model/types.py
Changed treat_dot_as_module parameter from bool = False to `bool
Parser Constructors
src/datamodel_code_generator/parser/base.py, src/datamodel_code_generator/parser/graphql.py, src/datamodel_code_generator/parser/jsonschema.py, src/datamodel_code_generator/parser/openapi.py
Updated Parser class constructors to accept `treat_dot_as_module: bool
Reference Resolution
src/datamodel_code_generator/reference.py
Updated ModelResolver.__init__ to accept `treat_dot_as_module: bool
Unit Tests
tests/model/test_base.py
Updated test expectations for get_module_path: when treat_dot_as_module=False, paths now exclude file-based components. Split parametrized test into explicit test_get_module_path_without_file_path_treat_dot_true and test_get_module_path_without_file_path_treat_dot_false for clarity.
Test Data Input
tests/data/jsonschema/no_treat_dot_single/v0.0.39.job.json
Added new JSON Schema test input file for no-treat-dot scenario.
Test Expected Outputs
tests/data/expected/main/jsonschema/no_treat_dot_single/..., tests/data/expected/main/jsonschema/treat_dot_as_module_single_no_treat/..., tests/data/expected/main/jsonschema/treat_dot_single/...
Added generated test fixture directories and files including __init__.py modules and model files (v0_0_39_job.py, model_schema.py, nested v0/0/39/job.py) reflecting expected codegen output for different flag configurations.
Functional Tests
tests/main/jsonschema/test_main_jsonschema.py
Updated test_treat_dot_as_module signature from boolean parameter to extra_args and expected_suffix parameters. Added new tests: test_no_treat_dot_as_module_single_file and test_treat_dot_as_module_version_style with parameterized variations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Areas requiring extra attention:

  • src/datamodel_code_generator/model/base.py — Core logic changes in sanitize_module_name, get_module_path, and get_module_name to distinguish between None (unspecified), True (split dots), and False (keep dots as underscores); verify conditional branches are correct.
  • src/datamodel_code_generator/parser/base.py — The treat_dot_as_module or False coercion ensures internal consistency but affects the instance attribute; verify self.treat_dot_as_module remains potentially None for downstream logic as intended.
  • src/datamodel_code_generator/reference.py — Changes to get_class_name branching logic when treat_dot_as_module is None; ensure class name derivation matches expected semantics for the tri-state.
  • src/datamodel_code_generator/types.py — Assignment of self.treat_dot_as_module = treat_dot_as_module or False and its impact on model field metadata generation.
  • Test expectations — Multiple test fixtures added for new no_treat_dot and version-style naming scenarios; verify generated output matches expectations across all test cases.

Possibly related PRs

Suggested labels

safe-to-fix

Suggested reviewers

  • ilovelinux

Poem

🐰 A tri-state flag hops into place,
No longer binary, with elegant grace,
Dots split or flatten, as the user may choose,
With None standing neutral—nothing to lose!
From CLI to core, the change flows so clean,
The finest refactor this bunny has seen!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a --no-treat-dot-as-module option to provide flat output structure as an alternative to the existing modular behavior.
Linked Issues check ✅ Passed The PR successfully addresses issue #1535 by implementing the requested feature to disable the 'modular schema' splitting behavior. The changes introduce a new --no-treat-dot-as-module flag that allows users to keep dots in names as underscores instead of creating nested directory structures, directly resolving the versioned schema name problem.
Out of Scope Changes check ✅ Passed All changes are in-scope and directly support the new --no-treat-dot-as-module option. Documentation, CLI arguments, type signatures, and test files are all properly aligned with the feature implementation and do not introduce unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 97.67% which is sufficient. The required threshold is 80.00%.

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

❤️ Share

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

🤖 Generated by GitHub Actions
@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 (e8ff0f8) to head (b7f74a7).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2732   +/-   ##
=======================================
  Coverage   99.36%   99.36%           
=======================================
  Files          83       83           
  Lines       12068    12081   +13     
  Branches     1456     1456           
=======================================
+ Hits        11991    12004   +13     
  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 #2732 will not alter performance

Comparing feature/no-treat-dot-as-module (b7f74a7) with main (e8ff0f8)

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.

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 (2)
docs/cli-reference/template-customization.md (1)

263-278: Documentation inconsistency: mismatched flag names.

The section is titled --no-treat-dot-as-module (line 263) and the reference link uses this name (line 277), but:

  • Line 267 references the old flag name: "The --treat-dot-as-module flag"
  • Line 274 shows usage with the old flag: --treat-dot-as-module

These should be updated to consistently use --no-treat-dot-as-module throughout the section.

🔎 Proposed fix
-The `--treat-dot-as-module` flag configures the code generation behavior.
+The `--no-treat-dot-as-module` flag configures the code generation behavior.

 !!! tip "Usage"

     ```bash
-    datamodel-codegen --input schema.json --treat-dot-as-module # (1)!
+    datamodel-codegen --input schema.json --no-treat-dot-as-module # (1)!
     ```
src/datamodel_code_generator/types.py (1)

843-856: Inconsistent use of treat_dot_as_module parameter in dynamic model creation.

On line 843, you correctly coerce None to False:

self.treat_dot_as_module: bool = treat_dot_as_module or False

However, on line 852, you pass the raw treat_dot_as_module parameter (which could still be None) to create_model:

treat_dot_as_module=(bool, treat_dot_as_module),

When treat_dot_as_module is None, this results in create_model receiving (bool, None) for a non-optional bool field, which could cause unexpected behavior or validation issues.

🔎 Proposed fix
         self.data_type: type[DataType] = create_model(
             "ContextDataType",
             python_version=(PythonVersion, python_version),
             use_standard_collections=(bool, use_standard_collections),
             use_generic_container=(bool, use_generic_container_types),
             use_union_operator=(bool, use_union_operator),
-            treat_dot_as_module=(bool, treat_dot_as_module),
+            treat_dot_as_module=(bool, self.treat_dot_as_module),
             use_serialize_as_any=(bool, use_serialize_as_any),
             __base__=DataType,
         )
🧹 Nitpick comments (12)
src/datamodel_code_generator/model/dataclass.py (1)

221-221: Clean up unused noqa directive.

The noqa: FBT001 directive on line 221 is no longer needed since the parameter type changed from bool to bool | None, which already addresses the boolean-trap concern that FBT001 warns about.

🔎 Proposed fix
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        treat_dot_as_module: bool | None = None,

Based on static analysis hints.

src/datamodel_code_generator/__main__.py (1)

454-454: Consider using consistent type annotation style.

This line uses Optional[bool] while other files in this PR use bool | None (e.g., dataclass.py line 65, base_model.py lines 291 and 348). While both are valid, the inconsistency is notable.

Since other fields in this Config class also use Optional[...] style, keeping Optional[bool] maintains local consistency. However, you could update the noqa comment or remove it if you decide to standardize on one style across the codebase.

Based on static analysis hints.

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

184-184: Remove unused noqa directive.

The # noqa: FBT001 comment is flagged as unused because the FBT001 rule is not enabled in your Ruff configuration.

🔎 Proposed fix
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        treat_dot_as_module: bool | None = None,
src/datamodel_code_generator/types.py (1)

828-828: Remove unused noqa directive.

The # noqa: FBT001 comment is flagged as unused because the FBT001 rule is not enabled in your Ruff configuration.

🔎 Proposed fix
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        treat_dot_as_module: bool | None = None,
src/datamodel_code_generator/model/types.py (1)

87-87: Remove unused noqa directive.

The # noqa: FBT001 comment is flagged as unused because the FBT001 rule is not enabled in your Ruff configuration.

🔎 Proposed fix
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        treat_dot_as_module: bool | None = None,
src/datamodel_code_generator/model/pydantic_v2/types.py (1)

72-99: Tri-state treat_dot_as_module looks good; drop unused noqa

The change to treat_dot_as_module: bool | None = None and its propagation into super().__init__ and create_model(...) is consistent with the new tri-state behavior and doesn’t introduce obvious correctness issues.

Ruff is right that # noqa: FBT001 is now unused; you can safely remove it to keep lint clean.

Proposed lint-only cleanup
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        treat_dot_as_module: bool | None = None,
src/datamodel_code_generator/reference.py (1)

499-555: Tri-state dotted-name handling is sound; remove unused noqa

The new logic in get_class_name:

  • Uses self.treat_dot_as_module is not False so that None and True both keep dotted module prefixes, while an explicit False flattens dots.
  • Replaces "." with "_" when modularization is disabled, ensuring resulting names stay valid and avoiding hidden dotted paths in the non-modular case.

This matches the intended --no-treat-dot-as-module behavior and keeps Reference.short_name consistent (no dots when flattening).

Ruff’s RUF100 note about # noqa: FBT001 on the constructor parameter is valid; that directive can be dropped.

Proposed lint-only cleanup
-        parent_scoped_naming: bool = False,  # noqa: FBT001, FBT002
-        treat_dot_as_module: bool | None = None,  # noqa: FBT001
+        parent_scoped_naming: bool = False,  # noqa: FBT001, FBT002
+        treat_dot_as_module: bool | None = None,

Also applies to: 848-883

tests/parser/test_openapi.py (1)

456-466: Tests correctly opt into modular output; consider flat-mode coverage

Using treat_dot_as_module=True in the alias and modular tests is a good way to lock in the modular output behavior now that the flag is tri-state.

You might optionally add a small companion test with treat_dot_as_module=False (or via the CLI flag that maps to it) to assert the new “flat output structure” behavior end-to-end, but it isn’t strictly required for this change set.

Also applies to: 468-477

tests/model/test_base.py (1)

302-353: Tests correctly capture new treat_dot_as_module semantics; consider adding a None case

The updated expectations for True vs False (with and without file_path) match the new get_module_path behavior. You may optionally add a small test for treat_dot_as_module=None to lock in the “backward compatible” default semantics described in the helper’s docstring.

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

188-220: Tri-state treat_dot_as_module is correctly threaded; clean up unused noqa

The new treat_dot_as_module: bool | None = None parameter is passed cleanly into the base DataModel both in __init__ and create_base_class_model, so Pydantic v2 models inherit the same behavior as the rest of the stack.

Ruff reports that the # noqa: FBT001 on the treat_dot_as_module argument (Line 288) is unused. You can drop that directive without changing behavior.

Also applies to: 281-309

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

127-161: msgspec Struct and DataTypeManager correctly propagate treat_dot_as_module; remove unused noqa

The added treat_dot_as_module: bool | None = None parameters in Struct.__init__, Struct.create_base_class_model, and DataTypeManager.__init__ are passed through consistently to the DataModel/type-manager base, matching the new tri-state design.

Ruff flags the # noqa: FBT001 directives on these new parameters (Lines 177 and 507) as unused. They’re safe to delete for a cleaner lint profile.

Also applies to: 170-193, 496-523

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

500-578: DataModel tri-state propagation is sound; drop unused noqa on create_base_class_model

Storing treat_dot_as_module on _treat_dot_as_module and feeding it into:

  • create_reuse_model(...)
  • module_path / module_name (via the helper functions)
  • create_base_class_model (through subclass overrides)

ensures that all DataModel instances—original, reused, and generic base—share consistent module naming behavior.

Ruff notes that the # noqa: FBT001 on the treat_dot_as_module parameter in create_base_class_model (Line 737) is unused; you can remove it safely.

Also applies to: 610-624, 709-717, 731-738

📜 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 0906812 and 0b428ed.

📒 Files selected for processing (31)
  • docs/cli-reference/index.md
  • docs/cli-reference/quick-reference.md
  • docs/cli-reference/template-customization.md
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/arguments.py
  • src/datamodel_code_generator/cli_options.py
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/model/dataclass.py
  • src/datamodel_code_generator/model/enum.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/model/pydantic/base_model.py
  • src/datamodel_code_generator/model/pydantic/types.py
  • src/datamodel_code_generator/model/pydantic_v2/base_model.py
  • src/datamodel_code_generator/model/pydantic_v2/types.py
  • src/datamodel_code_generator/model/scalar.py
  • src/datamodel_code_generator/model/typed_dict.py
  • src/datamodel_code_generator/model/types.py
  • src/datamodel_code_generator/model/union.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/graphql.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • src/datamodel_code_generator/reference.py
  • src/datamodel_code_generator/types.py
  • tests/data/expected/parser/openapi/openapi_parser_parse_alias/fo_o/__init__.py
  • tests/data/expected/parser/openapi/openapi_parser_parse_modular/foo/__init__.py
  • tests/data/expected/parser/openapi/openapi_parser_parse_modular/nested/__init__.py
  • tests/data/expected/parser/openapi/openapi_parser_parse_modular/woo/__init__.py
  • tests/model/test_base.py
  • tests/parser/test_openapi.py
💤 Files with no reviewable changes (1)
  • tests/data/expected/parser/openapi/openapi_parser_parse_alias/fo_o/init.py
🧰 Additional context used
🧬 Code graph analysis (6)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/woo/__init__.py (7)
tests/data/expected/parser/openapi/openapi_parser_parse_additional_properties/with_import_format.py (3)
  • Error (39-44)
  • Id (31-32)
  • Result (51-52)
tests/data/expected/parser/openapi/openapi_parser_parse/with_import.py (3)
  • Error (34-36)
  • Id (26-27)
  • Result (54-55)
tests/data/expected/main_kr/main/output.py (3)
  • Error (38-40)
  • Id (30-31)
  • Result (66-67)
tests/data/expected/parser/openapi/openapi_parser_parse/with_import_format.py (3)
  • Error (36-38)
  • Id (28-29)
  • Result (56-57)
tests/data/expected/parser/openapi/openapi_parser_parse_alias/__init__.py (4)
  • Error (17-19)
  • Id (35-36)
  • Result (39-40)
  • Source (43-44)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/_internal.py (1)
  • OptionalModel (10-11)
src/datamodel_code_generator/parser/base.py (2)
  • Result (646-651)
  • Source (654-666)
tests/model/test_base.py (1)
src/datamodel_code_generator/model/base.py (1)
  • get_module_path (422-440)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/nested/__init__.py (3)
src/datamodel_code_generator/__init__.py (1)
  • Error (312-321)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/_internal.py (1)
  • OptionalModel (10-11)
src/datamodel_code_generator/parser/base.py (2)
  • Result (646-651)
  • Source (654-666)
src/datamodel_code_generator/reference.py (1)
src/datamodel_code_generator/model/base.py (3)
  • name (671-673)
  • class_name (692-694)
  • class_name (697-701)
tests/parser/test_openapi.py (1)
src/datamodel_code_generator/parser/openapi.py (1)
  • OpenAPIParser (175-914)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/foo/__init__.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/_internal.py (1)
  • OptionalModel (10-11)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/model/types.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/pydantic_v2/types.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/pydantic_v2/base_model.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/pydantic/types.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/dataclass.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/reference.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/types.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/__main__.py

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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/msgspec.py

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

Remove unused noqa directive

(RUF100)


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

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/model/base.py

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

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: benchmarks
🔇 Additional comments (19)
src/datamodel_code_generator/model/pydantic/base_model.py (1)

291-291: LGTM!

The parameter type changes are consistent with the broader refactoring to make treat_dot_as_module optional across the codebase.

Also applies to: 348-348

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

60-60: LGTM!

The parameter type change is consistent with the broader refactoring.

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

64-64: LGTM!

The parameter type change is consistent with the broader refactoring.

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

121-121: LGTM!

Documentation updates correctly reflect the new --no-treat-dot-as-module flag naming.

Also applies to: 226-226

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

264-264: LGTM!

The parameter type change is consistent with the broader refactoring to support optional treat_dot_as_module behavior.

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

114-114: LGTM!

The documentation correctly reflects the new --no-treat-dot-as-module CLI option and is properly placed in the alphabetical index.

src/datamodel_code_generator/__init__.py (1)

467-467: LGTM!

The parameter type change from bool to bool | None correctly enables the optional/unspecified state for the treat_dot_as_module parameter in the public API.

tests/data/expected/parser/openapi/openapi_parser_parse_modular/woo/__init__.py (1)

1-3: LGTM!

The test expected output correctly shows the new modular structure with imports from ._internal and a properly declared __all__ for the public API.

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

180-180: LGTM!

The parameter type change from bool to bool | None is consistent with the broader refactoring and correctly propagates through the parser initialization chain.

tests/data/expected/parser/openapi/openapi_parser_parse_modular/nested/__init__.py (1)

1-3: LGTM!

The test expected output correctly shows the new modular structure with imports from ._internal and a properly declared __all__ for the public API.

src/datamodel_code_generator/cli_options.py (1)

168-181: Canonical CLI option for treat-dot-as-module is consistent

Documenting --no-treat-dot-as-module as the canonical option and registering it in CLI_OPTION_META fits the canonicalization strategy (longest option string) and should keep the docs/argparse sync logic happy.

tests/data/expected/parser/openapi/openapi_parser_parse_modular/foo/__init__.py (1)

1-3: Updated modular exports and __all__ look consistent

The re-export from . _internal and matching __all__ list align with the other modular expected packages and should reflect the new naming behavior correctly.

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

29-63: Union base correctly adopts optional treat_dot_as_module

Allowing treat_dot_as_module: bool | None = None and forwarding it into super().__init__ keeps GraphQL union models consistent with the rest of the model types under the new tri-state behavior.

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

54-88: TypedDict now participates in tri-state treat_dot_as_module

The widened treat_dot_as_module parameter and its forwarding into super().__init__ align TypedDict models with the rest of the codegen pipeline’s dotted-name handling.

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

511-607: JsonSchemaParser correctly propagates optional treat_dot_as_module

Widening treat_dot_as_module to bool | None in JsonSchemaParser.__init__ and forwarding it to super().__init__ keeps the JSON Schema pipeline consistent with the new tri-state behavior and allows explicit “flat” vs modular control via the shared infrastructure. The rest of the uses of self.treat_dot_as_module remain coherent with that design.

Also applies to: 688-704

src/datamodel_code_generator/arguments.py (1)

267-272: Tri-state CLI flag wiring for --treat-dot-as-module looks consistent

Using BooleanOptionalAction with default=None fits the new bool | None semantics and matches other options in this file. The help text clearly explains the positive and negative forms; no issues from this side.

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

409-446: Module naming helpers correctly implement tri-state behavior

The updated sanitize_module_name, get_module_path, and get_module_name encode the documented semantics:

  • True: preserve dots in sanitized stems and split names on dots.
  • False: sanitize stems (no dots) and avoid name-based splitting.
  • None: split names on dots but sanitize stems (back-compat).

This lines up with the new tests in tests/model/test_base.py.

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

676-789: Tri-state parameter threading is consistent with DataTypeManager's bool-only design; verify it remains sufficient

The Parser accepts treat_dot_as_module: bool | None = None and correctly threads it:

  • To DataTypeManager coerced as treat_dot_as_module or False (line 786) → only bool semantics used
  • To ModelResolver preserving tri-state (line 895) → explicitly checks is not False (reference.py:857)
  • On self preserving tri-state (line 920) → used in parse() truthy check (line 2918)

DataTypeManager's treat_dot_as_module: bool = False field (types.py:337) means it has no need to distinguish None from False. The coercion via or False is appropriate if this remains true. However, if DataTypeManager's type behavior must someday distinguish the "backward compatible default" (None) from explicit False, the or False coercion will need to be removed and the field type changed to accept tri-state.

For now, the wiring is sound because DataTypeManager only needs binary semantics while ModelResolver correctly leverages the tri-state information.


2915-2923: Confirm that the truthiness check for treat_dot_as_module correctly handles the tri-state parameter

The code accepts treat_dot_as_module: bool | None = None but stores the raw value in self.treat_dot_as_module and later checks it with if self.treat_dot_as_module. This truthiness check groups None with False, reserving the modular postprocessing only for explicit True. While this appears intentional (the parameter accepts None as the default), tests only verify True and False cases—the None case behavior is undocumented. Verify this matches the intended backward-compatible semantics.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

371-476: Remove unused noqa on treat_dot_as_module

Ruff flags # noqa: UP045 on Line 455 as unused. Since this field is correctly typed as Optional[bool] and UP045 isn’t enabled, the noqa is unnecessary noise.

You can safely drop the # noqa: UP045 comment.

Minimal cleanup
-    treat_dot_as_module: Optional[bool] = None  # noqa: UP045
+    treat_dot_as_module: Optional[bool] = None
🧹 Nitpick comments (4)
src/datamodel_code_generator/parser/base.py (2)

676-773: Check tri-state semantics between Parser, DataTypeManager, and ModelResolver

You now accept treat_dot_as_module: bool | None = None, but:

  • DataTypeManager is constructed with treat_dot_as_module=treat_dot_as_module or False (Line 787), coercing None to False.
  • ModelResolver still receives the raw treat_dot_as_module (Line 896).
  • self.treat_dot_as_module is stored as the raw value (Line 922).

This means None and False are indistinguishable for DataTypeManager, but may differ wherever ModelResolver or other components interpret None specially.

If the intent is that None behave exactly like False everywhere, this is fine. If instead None is supposed to mean “auto” or “inherit default” for name/module resolution, you might need to avoid the or False coercion and/or normalize once up-front.

Example adjustment if `None` should be preserved
-        self.data_type_manager: DataTypeManager = data_type_manager_type(
+        # If DataTypeManager now understands tri-state semantics, avoid
+        # coercing None to False here.
+        self.data_type_manager: DataTypeManager = data_type_manager_type(
@@
-            target_datetime_class=target_datetime_class,
-            treat_dot_as_module=treat_dot_as_module or False,
+            target_datetime_class=target_datetime_class,
+            treat_dot_as_module=treat_dot_as_module if treat_dot_as_module is not None else False,

2917-2924: Confirm intended default for treat_dot_as_module=None in parse()

The final return branches on truthiness:

return (
    self.__postprocess_result_modules(results)
    if self.treat_dot_as_module
    else { ...flattening logic... }
)

So treat_dot_as_module values False and None both take the “flatten” branch. If None is meant to be distinct from an explicit False (e.g., to preserve previous default behavior while allowing explicit opt‑out), this code doesn’t differentiate them.

Please confirm that “unspecified” (None) is indeed supposed to behave identically to False here; otherwise you may want to branch explicitly on is True / is False.

src/datamodel_code_generator/__main__.py (1)

83-87: Consider adding treat_dot_as_module to BOOLEAN_OPTIONAL_OPTIONS

You’ve migrated treat_dot_as_module to an Optional[bool] flag (BooleanOptionalAction on the CLI), but BOOLEAN_OPTIONAL_OPTIONS currently only includes use_specialized_enum and use_standard_collections. As a result, generate_cli_command() will emit --treat-dot-as-module for True but nothing for False, even though --no-treat-dot-as-module exists.

Adding treat_dot_as_module here would let generate_cli_command round-trip pyproject configs more faithfully.

Diff to include `treat_dot_as_module`
-BOOLEAN_OPTIONAL_OPTIONS: frozenset[str] = frozenset({
-    "use_specialized_enum",
-    "use_standard_collections",
-})
+BOOLEAN_OPTIONAL_OPTIONS: frozenset[str] = frozenset({
+    "use_specialized_enum",
+    "use_standard_collections",
+    "treat_dot_as_module",
+})
src/datamodel_code_generator/arguments.py (1)

274-279: LGTM! CLI argument properly updated for tri-state behavior.

The use of BooleanOptionalAction correctly provides both --treat-dot-as-module and --no-treat-dot-as-module flags with a None default for the unspecified case. The help text clearly explains both behaviors.

💡 Optional: Consider clarifying default behavior in help text

The help text explains both flag behaviors but doesn't explicitly state what happens when neither flag is specified (the None default). Consider adding a sentence like:

     "--treat-dot-as-module",
     help="Treat dotted schema names as module paths, creating nested directory structures (e.g., 'foo.bar.Model' "
-    "becomes 'foo/bar.py'). Use --no-treat-dot-as-module to keep dots in names as underscores for single-file output.",
+    "becomes 'foo/bar.py'). Use --no-treat-dot-as-module to keep dots in names as underscores for single-file output. "
+    "Default behavior (when neither flag is specified) splits names while sanitizing file paths.",
     action=BooleanOptionalAction,
     default=None,

This is optional and doesn't affect functionality.

📜 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 0b428ed and 7a31127.

📒 Files selected for processing (22)
  • docs/cli-reference/index.md
  • docs/cli-reference/quick-reference.md
  • src/datamodel_code_generator/__init__.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/arguments.py
  • src/datamodel_code_generator/cli_options.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/graphql.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/parser/openapi.py
  • tests/data/expected/main/jsonschema/no_treat_dot_single/__init__.py
  • tests/data/expected/main/jsonschema/no_treat_dot_single/v0_0_39_job.py
  • tests/data/expected/main/jsonschema/treat_dot_as_module_single_no_treat/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_as_module_single_no_treat/model_schema.py
  • tests/data/expected/main/jsonschema/treat_dot_single/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/0/39/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/0/39/job.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/0/__init__.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/__init__.py
  • tests/data/jsonschema/no_treat_dot_single/v0.0.39.job.json
  • tests/main/jsonschema/test_main_jsonschema.py
  • tests/model/test_base.py
✅ Files skipped from review due to trivial changes (7)
  • tests/data/expected/main/jsonschema/treat_dot_as_module_single_no_treat/model_schema.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/0/39/init.py
  • tests/data/expected/main/jsonschema/treat_dot_as_module_single_no_treat/init.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/0/init.py
  • tests/data/expected/main/jsonschema/treat_dot_single/init.py
  • tests/data/expected/main/jsonschema/no_treat_dot_single/init.py
  • tests/data/expected/main/jsonschema/treat_dot_single/v0/init.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/datamodel_code_generator/cli_options.py
  • docs/cli-reference/index.md
🧰 Additional context used
🧬 Code graph analysis (2)
tests/data/expected/main/jsonschema/no_treat_dot_single/v0_0_39_job.py (2)
tests/data/expected/main/jsonschema/treat_dot_single/v0/0/39/job.py (1)
  • Job (10-12)
src/datamodel_code_generator/model/base.py (1)
  • name (671-673)
tests/model/test_base.py (1)
src/datamodel_code_generator/model/base.py (1)
  • get_module_path (422-440)
🪛 Ruff (0.14.8)
src/datamodel_code_generator/__main__.py

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

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). (9)
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Ubuntu
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (17)
tests/data/jsonschema/no_treat_dot_single/v0.0.39.job.json (1)

1-14: LGTM!

The JSON Schema is well-structured and serves as an appropriate test fixture for the new --no-treat-dot-as-module option. The filename with version-style dots (v0.0.39.job.json) directly addresses the issue described in #1535, ensuring that versioned schema names won't be incorrectly split into nested module paths.

tests/data/expected/main/jsonschema/treat_dot_single/v0/0/39/job.py (1)

1-12: LGTM! Clean generated code structure.

The generated Pydantic model is correct and follows best practices. The file demonstrates the expected output format when dots in schema names are treated as module separators (creating the v0/0/39/ directory structure from the original "v0.0.39.job.json" schema name). As a test fixture, this properly validates the generation behavior.

tests/data/expected/main/jsonschema/no_treat_dot_single/v0_0_39_job.py (1)

1-12: Expected output file matches new no-treat-dot behavior

The model structure and filename (v0_0_39_job.py) correctly reflect the flat, no-dot-as-module layout; nothing to change here.

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

180-280: OpenAPIParser tri-state treat_dot_as_module wiring is consistent

Changing the ctor parameter to bool | None = None and forwarding it unchanged into super().__init__ keeps behavior aligned with the base Parser while allowing the new tri‑state. No issues spotted here.


647-759: Passing self.treat_dot_as_module into _create_data_model is appropriate

Propagating the parser-level treat_dot_as_module value into parameter models ensures consistent handling between operation-parameter models and other generated models. This looks correct.

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

97-196: GraphQLParser treat_dot_as_module propagation is consistent with Parser

The ctor now takes treat_dot_as_module: bool | None = None and forwards it to super().__init__, matching the base Parser’s signature and behavior. No issues found.


582-621: Passing treat_dot_as_module into _create_data_model for GraphQL objects

Including treat_dot_as_module=self.treat_dot_as_module when creating object-like models keeps GraphQL behavior aligned with JSON/OpenAPI models. Looks correct.

src/datamodel_code_generator/__main__.py (1)

668-781: Config → generate() wiring for tri-state treat_dot_as_module looks correct

Config.treat_dot_as_module: Optional[bool] is passed through run_generate_from_config() into generate(..., treat_dot_as_module=config.treat_dot_as_module, ...), matching the updated public API. No behavioral issues seen here.

src/datamodel_code_generator/__init__.py (2)

382-488: Public generate() API updated cleanly to Optional[bool]

The generate() signature now accepts treat_dot_as_module: bool | None = None, and forwards this directly into the selected parser ctor. This keeps the public API aligned with Parser/OpenAPIParser/GraphQLParser without breaking existing callers that pass True/False. Looks good.


633-734: Parser construction correctly forwards treat_dot_as_module

Within generate(), the parser_class(...) call passes treat_dot_as_module=treat_dot_as_module, ensuring the tri‑state flag from CLI/Config reaches the parser layer. No additional changes needed here.

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

594-594: LGTM! Parameter signature updated correctly for tri-state behavior.

The change from bool = False to bool | None = None properly supports the new tri-state flag behavior (True/False/None) introduced by the --no-treat-dot-as-module option. The parameter is correctly forwarded to the parent class.

tests/model/test_base.py (3)

306-306: LGTM! Test expectation correctly updated for flat output mode.

When treat_dot_as_module=False, the new behavior correctly:

  • Sanitizes the file stem by replacing dots with underscores (array_commons_schema)
  • Omits the name-based module hierarchy (no array-commons component)

This aligns with the flat output structure goal of the --no-treat-dot-as-module option.


316-327: LGTM! Explicit tests improve clarity for tri-state behavior.

Splitting the combined test into two explicit cases makes the behavioral difference clear:

  • treat_dot_as_module=True: Splits dotted names into module hierarchy ["my_module"]
  • treat_dot_as_module=False: Returns empty list [] (flat structure, no hierarchy)

Both expectations correctly match the implementation logic.


336-338: LGTM! Parametrized test expectations correctly updated.

The False cases now consistently expect empty lists [], matching the flat output behavior where dotted names are not split into module hierarchies.

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

356-372: LGTM! Excellent parameterization for tri-state behavior.

The refactored test properly covers all three states of the treat_dot_as_module parameter:

  • Explicit enable with --treat-dot-as-module
  • Default/unspecified (None)
  • Explicit disable with --no-treat-dot-as-module

Both the default and explicit disable correctly map to the same expected output ("treat_dot_not_as_module"), which aligns with the PR objective of providing an explicit flag to disable dot-splitting behavior.


393-409: LGTM! Comprehensive test for the new flag.

This test properly validates the --no-treat-dot-as-module flag in single-file mode, addressing the core issue from #1535. The CLI documentation marker ensures this important option is properly documented for users who need to preserve dotted names (like versioned schemas) without splitting them into modules.


412-429: LGTM! Excellent coverage for version-style schema names.

This test directly addresses the motivating use case from issue #1535 (versioned schema names like "v0.0.39_jobs_response"). The parameterization ensures both the splitting and flat-output behaviors work correctly for these real-world naming patterns, preventing awkward generated filenames like v0/field_0.py.

Comment thread docs/cli-reference/quick-reference.md Outdated
@koxudaxi koxudaxi merged commit 8c7e077 into main Dec 22, 2025
38 checks passed
@koxudaxi koxudaxi deleted the feature/no-treat-dot-as-module branch December 22, 2025 13:44
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.

More flexible "Modular Schema" support (problems with versioned types)

1 participant