Skip to content

Move coverage fail_under check to combined coverage environment#2909

Merged
koxudaxi merged 30 commits intomainfrom
feature/increase-coverage-threshold
Jan 3, 2026
Merged

Move coverage fail_under check to combined coverage environment#2909
koxudaxi merged 30 commits intomainfrom
feature/increase-coverage-threshold

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Jan 2, 2026

Summary by CodeRabbit

  • New Features

    • Generate Msgspec Struct models with UNSET-aware optional fields; add simpleUnion to Options
    • Minimized-prefix collision resolution and new re-exports to avoid naming conflicts
  • Tests

    • Added several MSGSPEC-related tests (including inline-const and oneof variants), expanded collision-resolution tests; some test housekeeping and duplicated test insertions
  • Documentation

    • Updated CLI/model customization docs to document the simpleUnion option

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 2, 2026

📝 Walkthrough

Walkthrough

Adjusts many test-coverage pragmas and pytest/coverage flags, adds msgspec-generated expectations and tests, always attempts Pydantic model rebuild during schema loading, improves import removal cleanup, and propagates collection/union options into the GraphQL parser.

Changes

Cohort / File(s) Summary
Coverage & Test Invocation
pyproject.toml, tox.ini
Changed coverage thresholds/flags (--cov-fail-under=0, coverage --fail-under=100), extended omit patterns; alters CI/test-failure behavior and reporting flags.
Bulk coverage annotations
src/datamodel_code_generator/...
__main__.py, model/msgspec.py, prompt.py, reference.py, types.py, config.py, util.py, validators.py, parser/..., model/...
Added/removed many # pragma: no cover / # pragma: no branch markers across core modules; no functional logic changes but changes affect coverage reporting and branch visibility.
Format API
src/datamodel_code_generator/format.py
Added PythonVersion.has_type_alias(self) -> bool (removed duplicate), minor coverage annotations.
Input model rebuild
src/datamodel_code_generator/input_model.py
_load_single_model_schema now unconditionally calls _try_rebuild_model(obj) for Pydantic BaseModel objects (removed previous hasattr guard) — changes control flow for Pydantic model handling.
Imports cleanup
src/datamodel_code_generator/imports.py
remove() now prunes empty containers and alias maps after decrementing counters for both future and local-import branches; internal cleanup behavior tightened.
GraphQL parser config propagation
src/datamodel_code_generator/parser/graphql.py
GraphQLParser.__init__ now stores use_standard_collections and use_union_operator from config/options on the instance; minor exception/coverage cleanups.
Msgspec outputs & tests
tests/data/expected/main/openapi/...
msgspec_*.py, nullable*.py, typed_dict_*.py
Added/updated multiple expected generated modules for msgspec Struct models, union/UNSET handling, and added simpleUnion field variants across several expected outputs.
Tests added/modified/removed
tests/main/openapi/..., tests/main/..., tests/*
Added several msgspec-focused tests (some duplicated), added collision-resolution test, removed test_main_without_arguments, deleted/modified various test classes and helpers; many pragma removals in test files.
CLI-doc & test infra
tests/conftest.py, tests/main/conftest.py, tests/cli_doc/*
Refined CLI-doc marker collection/validation, removed coverage-suppression markers, deleted TestCoverageStats, adjusted pytest collection helpers and docstrings.
Test helpers / parser tests cleanup
tests/model/test_base.py, tests/parser/test_base.py, tests/test_input_model.py
Removed several test helper methods/fixtures and simplified mocks; some test behavior/mocks changed (affects test scaffolding).
Collision example outputs
tests/data/expected/main/openapi/all_exports_collision_success/...
Added package/modules demonstrating minimal-prefix collision resolution and aliased re-exports.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

safe-to-fix

Suggested reviewers

  • ilovelinux

Poem

🐰 I hopped through code and nudged each pragma free,
Rebuilt models gently, pruned imports with glee,
Msgspec fields now bloom and tests align,
A tidy burrow of types, neat by design,
I thumped a happy carrot for CI to see.

Pre-merge checks and finishing touches

✅ Passed checks (3 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: moving a coverage fail_under check from pytest invocation to the combined coverage environment in tox.ini.
Docstring Coverage ✅ Passed Docstring coverage is 86.84% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@koxudaxi koxudaxi marked this pull request as draft January 2, 2026 20:51
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 2, 2026

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

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jan 2, 2026

CodSpeed Performance Report

Merging #2909 will degrade performance by 16.84%

Comparing feature/increase-coverage-threshold (3f2b713) with main (c83470e)

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

Summary

❌ 11 regressions
⏩ 98 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Mode Benchmark BASE HEAD Efficiency
WallTime test_perf_deep_nested 5.1 s 6 s -15.24%
WallTime test_perf_duplicate_names 839.6 ms 1,002.1 ms -16.21%
WallTime test_perf_multiple_files_input 3.1 s 3.8 s -16.52%
WallTime test_perf_large_models_pydantic_v2 3.1 s 3.7 s -16.84%
WallTime test_perf_all_options_enabled 5.7 s 6.7 s -14.56%
WallTime test_perf_graphql_style_pydantic_v2 695.7 ms 820.7 ms -15.23%
WallTime test_perf_complex_refs 1.7 s 2 s -16.34%
WallTime test_perf_kubernetes_style_pydantic_v2 2.2 s 2.6 s -16.69%
WallTime test_perf_openapi_large 2.5 s 2.9 s -15.28%
WallTime test_perf_aws_style_openapi_pydantic_v2 1.6 s 1.9 s -14.84%
WallTime test_perf_stripe_style_pydantic_v2 1.7 s 2 s -16.62%

Footnotes

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

@koxudaxi koxudaxi changed the title Increase coverage threshold from 88% to 100% Move coverage fail_under check to combined coverage environment Jan 2, 2026
@koxudaxi koxudaxi marked this pull request as ready for review January 3, 2026 01:31
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/datamodel_code_generator/model/msgspec.py (2)

215-220: API parameter ignored but preserved for compatibility.

The use_union_operator parameter is no longer used in the implementation - the function now always uses UNION_OPERATOR_DELIMITER (line 220) and passes use_union_operator=True to helper functions (line 217). The parameter is kept for backward API compatibility.

However, the static analysis correctly identifies that the noqa: FBT001 directive is unnecessary:

🔎 Fix unused noqa directive
-def get_neither_required_nor_nullable_type(type_: str, use_union_operator: bool) -> str:  # noqa: ARG001, FBT001
+def get_neither_required_nor_nullable_type(type_: str, use_union_operator: bool) -> str:  # noqa: ARG001

224-226: API parameter ignored but preserved for compatibility.

Similar to the function above, use_union_operator is ignored and the function always uses UNION_OPERATOR_DELIMITER.

The noqa: FBT001 directive is unnecessary per static analysis:

🔎 Fix unused noqa directive
-def _add_unset_type(type_: str, use_union_operator: bool) -> str:  # noqa: ARG001, FBT001
+def _add_unset_type(type_: str, use_union_operator: bool) -> str:  # noqa: ARG001
action.yml (1)

103-103: Consider handling extra-args through the ARGS array for robustness.

The current approach of directly interpolating ${{ inputs.extra-args }} works for typical use cases, but handling it through the ARGS array would be more robust for edge cases with complex quoting.

🔎 Proposed refactor
         if [ -n "${{ inputs.profile }}" ]; then
           ARGS+=(--profile "${{ inputs.profile }}")
         fi
+
+        if [ -n "${{ inputs.extra-args }}" ]; then
+          ARGS+=(${{ inputs.extra-args }})
+        fi
 
-        datamodel-codegen "${ARGS[@]}" ${{ inputs.extra-args }}
+        datamodel-codegen "${ARGS[@]}"

Note: This still relies on GitHub Actions interpolation for word splitting of extra-args, but centralizes all argument handling in one place.

📜 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 44934ce and d1f0535.

📒 Files selected for processing (6)
  • .github/workflows/config-types.yaml
  • action.yml
  • pyproject.toml
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/model/msgspec.py
  • tox.ini
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-02T08:25:19.839Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2890
File: tests/data/expected/main/jsonschema/ref_nullable_with_constraint.py:14-15
Timestamp: 2026-01-02T08:25:19.839Z
Learning: The datamodel-code-generator currently generates RootModel subclasses with an explicit `root` field annotation (e.g., `class StringType(RootModel[str]): root: str`). This is existing behavior of the code generator and should not be flagged as an issue introduced by new changes.

Applied to files:

  • src/datamodel_code_generator/__main__.py
🧬 Code graph analysis (2)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/__init__.py (1)
  • Error (300-309)
src/datamodel_code_generator/model/msgspec.py (1)
src/datamodel_code_generator/types.py (1)
  • _remove_none_from_union (298-359)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/model/msgspec.py

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

Remove unused noqa directive

(RUF100)


224-224: 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). (13)
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: py312-isort7 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (8)
pyproject.toml (1)

250-250: Coverage threshold enforcement moved to combined coverage environment.

Setting fail_under = 0 here is intentional - the coverage threshold is now enforced in the combined coverage environment in tox.ini (line 91) with --fail-under=100. This centralizes coverage checking after combining results from all test environments, which is a more accurate approach than checking coverage per environment.

tox.ini (2)

43-43: Per-environment coverage check disabled.

The --cov-fail-under=0 flag disables coverage threshold enforcement during individual test runs, deferring the check to the combined coverage environment. This aligns with the PR objective.


91-91: No changes needed — the 100% coverage threshold is already properly configured.

The --fail-under=100 requirement is an intentional, active part of the CI pipeline (the coverage environment that combines parallel test runs). The codebase already meets this threshold:

  • 35+ pragma: no cover markers are properly placed for platform-specific imports, error paths, and deprecated code
  • pyproject.toml explicitly omits untestable paths: tests/data/*, tests/main/test_performance.py, and */_types/*
  • The --skip-covered flag ensures only genuinely uncovered code fails the check
  • This environment is part of active CI, confirming the threshold is regularly met
.github/workflows/config-types.yaml (1)

23-33: Workflow refactored to use local action with profile-driven invocations.

The workflow now uses a local action (uses: ./) with different profile parameters instead of external actions and shell commands. This simplifies the workflow and aligns with the profile-based configuration approach defined in pyproject.toml.

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

390-392: Coverage exclusions aligned with PR objectives.

The # pragma: no cover annotations mark code paths not exercised by tests, which aligns with the PR's coverage strategy of requiring 100% coverage on tested paths while explicitly marking untested branches.

Also applies to: 394-395, 406-410, 421-422

src/datamodel_code_generator/__main__.py (1)

377-377: Coverage exclusion for untested error path.

The # pragma: no cover annotation marks this error path as intentionally excluded from coverage. This aligns with the PR's coverage strategy of achieving 100% coverage on tested code while explicitly marking untested edge cases.

action.yml (2)

10-23: Good change enabling profile-based configuration.

Making these inputs optional with empty defaults allows the action to work with profile-driven workflows where configuration is specified in pyproject.toml. This aligns well with the workflow changes mentioned in the PR summary.


77-93: Correct conditional argument construction.

The bash array handling is implemented correctly. The conditional checks ensure that only non-empty inputs are added to the command, which properly supports both explicit arguments and profile-based configuration.

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

99-99: Clean up unused noqa directive.

Static analysis (Ruff RUF100) reports that the noqa: PLR0913 directive is unused since PLR0913 (too-many-arguments) is not enabled. While the pragma: no cover annotation is appropriate, the unused noqa directive should be removed for code cleanliness.

🔎 Proposed fix
-            def dict(  # noqa: PLR0913  # pragma: no cover
+            def dict(  # pragma: no cover
                 self,
                 *,
📜 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 d1f0535 and b0ff0ec.

📒 Files selected for processing (8)
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/format.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/prompt.py
  • src/datamodel_code_generator/reference.py
  • src/datamodel_code_generator/types.py
  • tests/data/expected/main/openapi/msgspec_no_use_union_operator.py
  • tests/main/openapi/test_main_openapi.py
💤 Files with no reviewable changes (1)
  • src/datamodel_code_generator/format.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/datamodel_code_generator/model/msgspec.py
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-01-02T08:25:19.839Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2890
File: tests/data/expected/main/jsonschema/ref_nullable_with_constraint.py:14-15
Timestamp: 2026-01-02T08:25:19.839Z
Learning: The datamodel-code-generator currently generates RootModel subclasses with an explicit `root` field annotation (e.g., `class StringType(RootModel[str]): root: str`). This is existing behavior of the code generator and should not be flagged as an issue introduced by new changes.

Applied to files:

  • src/datamodel_code_generator/types.py
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/reference.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/__main__.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/__main__.py
🧬 Code graph analysis (4)
src/datamodel_code_generator/__main__.py (1)
src/datamodel_code_generator/__init__.py (1)
  • Error (300-309)
tests/data/expected/main/openapi/msgspec_no_use_union_operator.py (1)
src/datamodel_code_generator/model/msgspec.py (2)
  • Struct (109-209)
  • field (297-302)
src/datamodel_code_generator/reference.py (1)
src/datamodel_code_generator/parser/jsonschema.py (2)
  • root_id (756-758)
  • root_id (761-763)
tests/main/openapi/test_main_openapi.py (2)
tests/test_main_kr.py (1)
  • output_file (44-46)
tests/main/conftest.py (2)
  • output_file (99-101)
  • run_main_and_assert (245-409)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/reference.py

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

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

69-70: LGTM! Appropriate coverage exclusion for edge case.

The pragma: no cover annotation is appropriate here, as this else branch handles the rare case where an option lacks a description. The code logic is correct, and this annotation simply excludes an unlikely edge case from coverage requirements.

src/datamodel_code_generator/__main__.py (1)

377-377: LGTM! Appropriate coverage exclusions for edge case validations.

The pragma: no cover annotations are reasonable for these edge cases:

  • Lines 377 & 452: Validation error paths for keyword-only with incompatible Python versions (duplicated for Pydantic v1/v2 compatibility)
  • Line 720: Repository boundary heuristic when searching for pyproject.toml

These are defensive code paths that should rarely execute in normal usage, making them appropriate candidates for coverage exclusion.

Also applies to: 452-452, 720-720

src/datamodel_code_generator/reference.py (1)

770-770: LGTM! Appropriate coverage exclusion for edge case.

The pragma: no cover annotation is reasonable for this URL reference resolution edge case where the file part matches the root_id. This is a defensive check that should rarely execute in normal usage.

src/datamodel_code_generator/types.py (1)

347-348: LGTM! Appropriate coverage exclusions for edge cases.

The pragma: no cover annotations are reasonable for these edge cases:

  • Line 347: Recursive nested union prefix handling during None removal
  • Lines 650-657: Rare configuration where use_generic_container=True but use_standard_collections=False
  • Lines 781-782: Default SET handling path for non-standard, non-generic containers

These are defensive code paths or rare configuration combinations that are appropriate candidates for coverage exclusion.

Also applies to: 650-657, 781-782

tests/main/openapi/test_main_openapi.py (1)

3522-3538: LGTM! Well-structured test for msgspec without union operator.

This test appropriately adds coverage for the --no-use-union-operator flag with msgspec.Struct output. It complements the existing test_main_openapi_msgspec_use_union_operator (line 3453) by testing the opposite behavior—explicitly disabling the union operator syntax even when targeting Python 3.10+.

The test structure follows established patterns in the file, and the use of MSGSPEC_LEGACY_BLACK_SKIP is consistent with other msgspec tests.

tests/data/expected/main/openapi/msgspec_no_use_union_operator.py (3)

5-9: LGTM! Correct imports for Union syntax.

The imports correctly include Union from typing, which is necessary for the Union[X, Y] syntax demonstrated throughout this file. All msgspec-specific imports are also present.


12-47: LGTM! Proper Union syntax throughout Struct classes.

The generated Structs correctly use Union[X, Y] syntax instead of the union operator (X | Y), which aligns with the --no-use-union-operator flag. The combination of Union, Annotated, and UnsetType follows msgspec best practices for optional fields with metadata.

Examples:

  • Line 15: Union[str, UnsetType] with default value
  • Lines 32-35: Union[Annotated[str, Meta(...)], UnsetType] with UNSET default

50-72: LGTM! TypeAlias declarations use Optional consistently.

The TypeAlias declarations correctly use Optional[X] instead of the union operator syntax (X | None), maintaining consistency with the --no-use-union-operator flag throughout the generated code.

@koxudaxi koxudaxi force-pushed the feature/increase-coverage-threshold branch 2 times, most recently from a125025 to 864b084 Compare January 3, 2026 02:38
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

📜 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 b0ff0ec and 864b084.

⛔ Files ignored due to path filters (1)
  • tests/data/openapi/nullable.yaml is excluded by !tests/data/**/*.yaml and included by none
📒 Files selected for processing (17)
  • docs/cli-reference/model-customization.md
  • src/datamodel_code_generator/config.py
  • src/datamodel_code_generator/format.py
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/model/pydantic/__init__.py
  • src/datamodel_code_generator/model/pydantic_v2/__init__.py
  • src/datamodel_code_generator/util.py
  • src/datamodel_code_generator/validators.py
  • tests/data/expected/main/openapi/msgspec_no_use_union_operator.py
  • tests/data/expected/main/openapi/msgspec_nullable.py
  • tests/data/expected/main/openapi/msgspec_use_union_operator.py
  • tests/data/expected/main/openapi/nullable.py
  • tests/data/expected/main/openapi/nullable_strict_nullable.py
  • tests/data/expected/main/openapi/nullable_strict_nullable_use_union_operator.py
  • tests/data/expected/main/openapi/typed_dict_nullable.py
  • tests/data/expected/main/openapi/typed_dict_nullable_strict_nullable.py
  • tests/data/expected/main/openapi/use_default_kwarg.py
✅ Files skipped from review due to trivial changes (2)
  • docs/cli-reference/model-customization.md
  • src/datamodel_code_generator/config.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/datamodel_code_generator/model/msgspec.py
  • src/datamodel_code_generator/format.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:

  • src/datamodel_code_generator/model/pydantic_v2/__init__.py
  • src/datamodel_code_generator/util.py
📚 Learning: 2026-01-02T08:25:19.839Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2890
File: tests/data/expected/main/jsonschema/ref_nullable_with_constraint.py:14-15
Timestamp: 2026-01-02T08:25:19.839Z
Learning: The datamodel-code-generator currently generates RootModel subclasses with an explicit `root` field annotation (e.g., `class StringType(RootModel[str]): root: str`). This is existing behavior of the code generator and should not be flagged as an issue introduced by new changes.

Applied to files:

  • src/datamodel_code_generator/model/pydantic_v2/__init__.py
  • src/datamodel_code_generator/util.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/util.py
🧬 Code graph analysis (5)
tests/data/expected/main/openapi/use_default_kwarg.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
  • Field (6-7)
tests/data/expected/main/openapi/nullable.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
  • Field (6-7)
src/datamodel_code_generator/util.py (1)
src/datamodel_code_generator/reference.py (1)
  • _BaseModel (82-139)
tests/data/expected/main/openapi/nullable_strict_nullable_use_union_operator.py (1)
tests/data/expected/parser/openapi/openapi_parser_parse_modular/bar.py (1)
  • Field (6-7)
tests/data/expected/main/openapi/msgspec_no_use_union_operator.py (1)
src/datamodel_code_generator/model/type_alias.py (1)
  • TypeAlias (37-42)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/util.py

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

Remove unused noqa directive

(RUF100)


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

Remove unused noqa directive

(RUF100)

🔇 Additional comments (17)
src/datamodel_code_generator/model/pydantic_v2/__init__.py (1)

49-55: LGTM! Appropriate coverage exclusion for version-specific fallback.

The pragma: no cover annotation correctly excludes the Pydantic v1 fallback path when tests run exclusively with v2.

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

39-47: LGTM! Consistent coverage strategy.

The coverage exclusion mirrors the approach in pydantic_v2/__init__.py, appropriately excluding the v1 compatibility path.

src/datamodel_code_generator/validators.py (1)

43-51: LGTM! Appropriate exclusion for v2-only feature.

Since the validators feature is v2-only (as noted in the comment), excluding the v1 fallback path from coverage is reasonable.

src/datamodel_code_generator/util.py (5)

20-23: LGTM! Appropriate exclusion for environment-specific import fallback.

The pragma: no cover on the ImportError handler is reasonable, as testing both the stdlib tomllib (Python 3.11+) and the fallback tomli in a single environment is impractical.


64-82: LGTM! Reasonable exclusions for edge cases and environment-specific paths.

Both coverage exclusions are appropriate:

  • Line 66: Deprecated YAML bool format warning is an edge case
  • Line 81: CSafeLoader fallback is environment-dependent (C extension availability)

141-172: LGTM! Pydantic v1 compatibility path correctly excluded.

The coverage exclusions on lines 168 and 170 appropriately exclude the v1 root_validator path when tests run with v2.

Note: Ruff reports the # noqa: PLC0415 on line 168 as unused (RUF100), but based on learnings, these defensive noqa directives should be retained for lazy imports to prepare for potential future Ruff configuration changes.


175-191: LGTM! Consistent coverage strategy for field validators.

The coverage exclusions on lines 187 and 189 mirror the approach in model_validator, appropriately excluding v1 compatibility code.

Note: The RUF100 warning on line 187 should be ignored per the project's policy of retaining defensive # noqa: PLC0415 directives on lazy imports.


212-310: LGTM! Comprehensive v1 compatibility wrapper coverage exclusions.

All Pydantic v1 fallback paths are appropriately excluded from coverage (lines 224, 289, 296, 303, 310), consistent with the overall strategy when tests run exclusively with v2.

tests/data/expected/main/openapi/typed_dict_nullable.py (1)

68-70: LGTM!

The new union-typed fields are correctly defined as NotRequired with appropriate union types. The absence of None in the union types is consistent with the non-strict nullable behavior for TypedDict, where "nullable" translates to "optional key" rather than "value can be None".

tests/data/expected/main/openapi/nullable_strict_nullable_use_union_operator.py (1)

82-88: LGTM!

The new fields correctly use the union operator syntax (|) and include proper Field definitions with descriptions. The description "not nullable" on maybeValue while the type is str | int | None reflects accurate preservation of the OpenAPI schema's description—the generator correctly transfers source metadata even when it doesn't align with Python's nullability semantics.

tests/data/expected/main/openapi/msgspec_no_use_union_operator.py (1)

1-95: LGTM!

This new expected output file correctly demonstrates msgspec Struct generation without the union operator:

  • Uses Union[...] syntax consistently instead of | operator (e.g., Union[str, UnsetType] vs str | UnsetType)
  • Uses Optional[...] for type aliases (line 50, 69)
  • Properly imports from typing module (Union, Optional, Annotated, TypeAlias)
  • Field definitions with Meta descriptions and UNSET defaults are correctly structured

The file structure mirrors msgspec_use_union_operator.py with only the union syntax differing, which validates the --no-use-union-operator flag behavior.

tests/data/expected/main/openapi/msgspec_use_union_operator.py (1)

82-93: LGTM!

The new fields correctly use the union operator syntax with msgspec patterns:

  • Parenthesized unions for complex annotated types (lines 82-88, 89-92)
  • UnsetType for optional fields with UNSET default
  • Meta(description=...) for field metadata

The structure is consistent with the rest of the file and mirrors msgspec_no_use_union_operator.py with | syntax instead of Union[].

tests/data/expected/main/openapi/nullable.py (1)

82-88: LGTM!

The new fields are correctly defined:

  • maybeValue and nullableUnion use Field() with descriptions and None default
  • simpleUnion correctly uses a simple default assignment since it has no description metadata

Consistent with the other Pydantic expected output files.

tests/data/expected/main/openapi/typed_dict_nullable_strict_nullable.py (1)

68-70: LGTM!

The strict nullable variant correctly differentiates from the non-strict version:

  • nullableUnion includes None in the union (str | int | None) since the schema explicitly marks it as nullable
  • maybeValue and simpleUnion remain without None since they're not explicitly nullable in the schema

This properly validates the strict nullable mode preserves explicit nullability annotations.

tests/data/expected/main/openapi/nullable_strict_nullable.py (1)

82-88: LGTM!

The new fields are correctly added with union operator syntax, Field() wrappers for description metadata, and appropriate None defaults. The implementation is consistent with other Pydantic expected output files in this PR.

tests/data/expected/main/openapi/use_default_kwarg.py (1)

85-88: Patterns are consistent across versions. The three fields follow an intentional pattern: maybeValue and nullableUnion include descriptions (via Field() in Pydantic and Annotated[..., Meta(...)] in msgspec), while simpleUnion omits the description in both versions. The alignment with msgspec's union type handling is already correct.

tests/data/expected/main/openapi/msgspec_nullable.py (1)

82-93: Verify the semantic difference in nullable handling between Pydantic and msgspec versions.

The semantic difference is confirmed and correctly identified: the msgspec version implements "not nullable" for maybeValue using (str | int) | UnsetType (no None), whereas the Pydantic version uses str | int | None, making it nullable despite the description saying "not nullable". The TypedDict version uses NotRequired[str | int] without None, providing a third approach.

This reflects intentional library-specific design patterns:

  • msgspec: Uses UnsetType to distinguish unset (missing) fields from present values—enabling fine-grained control over optional vs. nullable semantics
  • Pydantic: Uses | None to represent both null values and default behavior, conflating nullable with optional
  • TypedDict: Uses NotRequired for optional fields without adding None for nullability

The consistent pattern across multiple expected outputs (msgspec_nullable.py, msgspec_use_union_operator.py, msgspec_no_use_union_operator.py, nullable.py, typed_dict_nullable.py, and strict_nullable variants) confirms this is intentional based on the code generator's design.

Comment thread tests/data/expected/main/openapi/use_default_kwarg.py Outdated
@koxudaxi koxudaxi force-pushed the feature/increase-coverage-threshold branch 2 times, most recently from 08e8c05 to 7ef06c1 Compare January 3, 2026 02:47
@koxudaxi koxudaxi force-pushed the feature/increase-coverage-threshold branch from da494f0 to af2e700 Compare January 3, 2026 02:53
Comment thread tests/parser/test_base.py Fixed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
tests/parser/test_base.py (1)

492-503: Remove unused fixture instead of excluding from coverage.

The escape_map fixture is not used anywhere in the test file. The test_character_escaping test uses the escape_characters import directly. Consider removing this fixture entirely rather than marking it with # pragma: no cover.

🔎 Suggested removal of unused fixture
-@pytest.fixture
-def escape_map() -> dict[str, str]:  # pragma: no cover
-    """Provide escape character mapping for tests."""
-    return {
-        "\u0000": r"\x00",  # Null byte
-        "'": r"\'",
-        "\b": r"\b",
-        "\f": r"\f",
-        "\n": r"\n",
-        "\r": r"\r",
-        "\t": r"\t",
-        "\\": r"\\",
-    }
-
-
tests/model/test_base.py (2)

43-45: Inconsistency with AI summary detected.

The AI summary states this method changed from a classmethod to an instance method, but the code still shows the @classmethod decorator on line 43 and uses the cls parameter. The method signature has not changed.

Additionally, the static analysis tool correctly identifies that the # noqa: D102 directive is unused because the D102 check is not enabled in your linting configuration.

The # pragma: no cover addition is appropriate for this stub method in a test helper class.

🔎 Optional cleanup to remove unused noqa directive
 @classmethod
-def get_data_type(cls, types: Types, **kwargs: Any) -> DataType:  # noqa: D102  # pragma: no cover
+def get_data_type(cls, types: Types, **kwargs: Any) -> DataType:  # pragma: no cover
     pass

56-58: Same inconsistency and unused directive as class B.

Similar to class B, the AI summary incorrectly states this method changed from a classmethod to an instance method. The @classmethod decorator remains on line 56, and the method signature uses cls, not self.

The # noqa: D102 directive is also unused here.

The # pragma: no cover addition is appropriate for this stub method.

🔎 Optional cleanup to remove unused noqa directive
 @classmethod
-def get_data_type(cls, types: Types, **kwargs: Any) -> DataType:  # noqa: D102  # pragma: no cover
+def get_data_type(cls, types: Types, **kwargs: Any) -> DataType:  # pragma: no cover
     pass
📜 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 e7b58d8 and 0447f7c.

📒 Files selected for processing (5)
  • tests/main/jsonschema/test_main_jsonschema.py
  • tests/main/openapi/test_main_openapi.py
  • tests/main/test_public_api_signature_baseline.py
  • tests/model/test_base.py
  • tests/parser/test_base.py
✅ Files skipped from review due to trivial changes (1)
  • tests/main/test_public_api_signature_baseline.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/main/openapi/test_main_openapi.py
🧰 Additional context used
🪛 Ruff (0.14.10)
tests/model/test_base.py

44-44: Unused noqa directive (non-enabled: D102)

Remove unused noqa directive

(RUF100)


57-57: Unused noqa directive (non-enabled: D102)

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.10 on macOS
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (3)
tests/parser/test_base.py (2)

39-44: LGTM! Appropriate coverage exclusion for abstract method stubs.

These abstract method implementations are required by the Parser base class but are never executed in tests. The # pragma: no cover annotations are correctly applied.


290-297: Remove or clarify the intention of # pragma: no cover annotations on test helper methods.

The __init__ assignment of self._data (line 293) and the render() method (lines 295-297) in class D are marked with # pragma: no cover, but class D is a test helper that exists solely to support test infrastructure. The pragmas are appropriate, but add a comment explaining that D is a minimal test helper class whose implementation details are not meant to be tested. Alternatively, if these methods will never be called during test execution (which appears to be the case), consider removing the methods entirely or documenting this intentional design.

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

288-293: Excluding the skipped CLI-exit test from coverage looks good

Adding # pragma: no cover to this always-skipped test_main_without_arguments keeps coverage accounting cleaner without changing behavior.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 3, 2026

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff             @@
##             main     #2909      +/-   ##
===========================================
+ Coverage   99.40%   100.00%   +0.59%     
===========================================
  Files          95        93       -2     
  Lines       16905     16836      -69     
  Branches     1990      1950      -40     
===========================================
+ Hits        16804     16836      +32     
+ Misses         52         0      -52     
+ Partials       49         0      -49     
Flag Coverage Δ
unittests 100.00% <100.00%> (+0.59%) ⬆️

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.

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 (2)
src/datamodel_code_generator/parser/jsonschema.py (1)

291-291: Remove unused noqa directive.

The # noqa: PLR1702 directive is not needed as the rule is not enabled. Clean this up to avoid confusion.

🔎 Proposed fix
-        if isinstance(value, list):  # pragma: no branch  # noqa: PLR1702
+        if isinstance(value, list):  # pragma: no branch
src/datamodel_code_generator/reference.py (1)

99-99: Remove unused noqa directive.

The # noqa: PLR0913 directive is not needed as the rule is not enabled. Clean this up to avoid confusion.

🔎 Proposed fix
-            def dict(  # noqa: PLR0913  # pragma: no cover
+            def dict(  # pragma: no cover
📜 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 0447f7c and be749b8.

📒 Files selected for processing (9)
  • src/datamodel_code_generator/__main__.py
  • src/datamodel_code_generator/format.py
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/reference.py
  • tests/conftest.py
  • tests/main/test_public_api_signature_baseline.py
  • tests/parser/test_base.py
✅ Files skipped from review due to trivial changes (1)
  • tests/conftest.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/datamodel_code_generator/parser/base.py
  • src/datamodel_code_generator/main.py
  • tests/parser/test_base.py
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-02T08:25:19.839Z
Learnt from: koxudaxi
Repo: koxudaxi/datamodel-code-generator PR: 2890
File: tests/data/expected/main/jsonschema/ref_nullable_with_constraint.py:14-15
Timestamp: 2026-01-02T08:25:19.839Z
Learning: The datamodel-code-generator currently generates RootModel subclasses with an explicit `root` field annotation (e.g., `class StringType(RootModel[str]): root: str`). This is existing behavior of the code generator and should not be flagged as an issue introduced by new changes.

Applied to files:

  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • src/datamodel_code_generator/reference.py
🧬 Code graph analysis (1)
src/datamodel_code_generator/reference.py (1)
src/datamodel_code_generator/parser/jsonschema.py (2)
  • root_id (756-758)
  • root_id (761-763)
🪛 Ruff (0.14.10)
src/datamodel_code_generator/parser/jsonschema.py

291-291: Unused noqa directive (non-enabled: PLR1702)

Remove unused noqa directive

(RUF100)

src/datamodel_code_generator/reference.py

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

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). (14)
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: py312-pydantic1 on Ubuntu
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.14 on Ubuntu
  • GitHub Check: 3.13 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (2)
src/datamodel_code_generator/model/base.py (1)

376-376: LGTM! Coverage annotations are appropriate.

Both # pragma: no branch annotations are correctly placed:

  • Line 376: The final elif in the examples handling chain—the uncovered branch is not meaningful to test
  • Line 916: Cache invalidation check where the else branch would be a no-op

These changes align with the PR's objective to adjust test coverage configuration without affecting runtime behavior.

Also applies to: 916-916

src/datamodel_code_generator/format.py (1)

107-119: Good practice: Deprecation warning for unused property.

The addition of a deprecation warning for the has_type_alias property is appropriate and follows Python best practices. The warning correctly uses DeprecationWarning with stacklevel=2 to point to the caller.

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 (5)
tests/test_input_model.py (1)

1370-1391: CWD duplication test behavior is fine; consider a slightly stricter assertion

The new precondition that inserts cwd into sys.path when missing makes test_input_model_cwd_already_in_path reliably exercise “already present” behavior and the final_count <= initial_count + 1 guard is reasonable.

If you want this test to assert that your implementation never adds a duplicate when cwd is already present, you could tighten it to final_count == initial_count in that branch and keep a separate test for the “missing cwd” case.

tests/main/conftest.py (1)

479-542: Output validation logic looks good; clean up unused noqa on _import_package

The updated _validate_output_files and _import_package paths correctly validate single files and packages (with timing and error recording) and are now properly covered.

Ruff reports the # noqa: PLR0912 on Line 491 as unused; since PLR0912 isn’t enabled, you can safely drop that directive to keep lint noise down.

Proposed cleanup for the unused noqa marker
-def _import_package(output_path: Path) -> None:  # noqa: PLR0912
+def _import_package(output_path: Path) -> None:
tests/conftest.py (3)

103-103: Remove unused noqa directives.

The PLR0912 and PLR0914 rules are not enabled in the project's Ruff configuration, making these noqa directives unnecessary. Only ARG001 is relevant here.

🔎 Suggested fix
-def _validate_cli_doc_marker(node_id: str, kwargs: CliDocKwargs) -> list[str]:  # noqa: ARG001, PLR0912, PLR0914
+def _validate_cli_doc_marker(node_id: str, kwargs: CliDocKwargs) -> list[str]:  # noqa: ARG001

276-277: Redundant Path() conversion.

CLI_DOC_COLLECTION_OUTPUT is already a Path object (defined on line 24), so wrapping it in Path() again is unnecessary.

🔎 Suggested fix
-    with Path(CLI_DOC_COLLECTION_OUTPUT).open("w", encoding="utf-8") as f:
+    with CLI_DOC_COLLECTION_OUTPUT.open("w", encoding="utf-8") as f:

472-474: Use public API or document the private method dependency.

Line 474 accesses _load_value(), a private API of the inline_snapshot library. While the code currently works, this creates a fragility risk since private methods can change without notice. Either:

  • Verify if get_snapshot_value() or another public API can replace this
  • Add documentation explaining why _load_value() is necessary and cannot be avoided
Code context
    else:
        # we need to normalize the external_file object's content as well
        assert _normalize_line_endings(expected._load_value()) == normalized_content
📜 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 ec06425 and 969bc66.

📒 Files selected for processing (9)
  • tests/cli_doc/test_cli_doc_coverage.py
  • tests/cli_doc/test_cli_options_sync.py
  • tests/conftest.py
  • tests/main/conftest.py
  • tests/main/openapi/test_main_openapi.py
  • tests/main/test_public_api_signature_baseline.py
  • tests/model/test_base.py
  • tests/parser/test_base.py
  • tests/test_input_model.py
💤 Files with no reviewable changes (1)
  • tests/model/test_base.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/main/openapi/test_main_openapi.py (2)
tests/main/conftest.py (2)
  • output_file (99-101)
  • run_main_and_assert (245-409)
tests/test_main_kr.py (1)
  • output_file (44-46)
tests/main/conftest.py (1)
tests/conftest.py (2)
  • assert_directory_content (563-593)
  • validate_generated_code (690-717)
🪛 Ruff (0.14.10)
tests/conftest.py

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

Remove unused noqa directive

(RUF100)

tests/main/conftest.py

491-491: 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-pydantic1 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.11 on Windows
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: py312-isort6 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Ubuntu
  • 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 (9)
tests/parser/test_base.py (1)

283-284: LGTM! Simplified test class is sufficient.

The minimal D class (now containing only a docstring) is adequate for its usage in tests. Since D is used exclusively as a type parameter (data_model_type=D) and not directly instantiated or invoked, removing the methods is appropriate cleanup aligned with the coverage-focused objectives of this PR.

tests/cli_doc/test_cli_options_sync.py (1)

32-118: CLI option sync tests now properly included in coverage

Including TestCLIOptionMetaSync in coverage is a sensible tightening; behavior is unchanged and the tests remain clear and robust.

tests/test_input_model.py (2)

30-49: Helper assertion guards are clearer and fully covered

Switching _assert_exit_code, _assert_stderr_contains, and _assert_file_exists to explicit if checks with pytest.fail (and no coverage suppression) keeps the helpers simple and makes their failure paths visible to coverage without changing semantics.


1125-1132: Pydantic v1 runtime mock remains correct with covered branch

The mock_hasattr logic keyed off call_count still correctly simulates a Pydantic v1 runtime for the first two checks and defers to the original hasattr afterward; removing coverage suppression here is safe and preserves the intended behavior.

tests/main/conftest.py (2)

132-164: Guard and validation branches are explicit and coverage-friendly

The various helpers (_assert_exit_code, _validate_extra_args, run_main_with_args, run_main_and_assert) now use straightforward if guards with pytest.fail and no coverage suppression. This keeps error paths well-documented, preserves prior behavior, and makes failures easier to diagnose in tests.

Also applies to: 216-243, 323-361, 367-407


423-461: Version/exec‑skip helpers handle invalid inputs robustly

_parse_target_version and _should_skip_exec now degrade gracefully on malformed --target-python-version values and maintain the intended logic around skipping compile/exec based on target/runtime and Pydantic model type. No functional regressions spotted.

tests/main/openapi/test_main_openapi.py (2)

3522-3572: New msgspec tests nicely extend nullable/oneOf/const coverage

The three added tests for msgspec (no_use_union_operator, oneof_with_null_no_use_union_operator, and inline_const) are consistent with the existing msgspec suite, reuse run_main_and_assert correctly, and exercise important combinations of --no-use-union-operator, oneOf with null, and inline const. Nothing problematic here.


3728-3787: Type‑alias Py3.11 tests now counted in coverage

Bringing the mutual/recursive type‑alias tests for Python 3.11 into coverage (Pydantic and msgspec variants) without changing their logic keeps the forward‑ref behavior well exercised across models and backends.

tests/cli_doc/test_cli_doc_coverage.py (1)

23-84: CLI doc coverage tracking remains correct and is now fully covered

The collected_options fixture and the two coverage/reporting test classes behave as before, but are now visible to coverage. Using get_canonical_option against _cli_doc_items continues to be a solid way to enforce and inspect CLI doc coverage.

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)
tests/main/conftest.py (1)

491-491: Remove unused noqa directive.

Static analysis indicates that PLR0912 (too-many-branches) is not enabled in the linter configuration, making this directive ineffective.

🔎 Proposed fix
-def _import_package(output_path: Path) -> None:  # noqa: PLR0912
+def _import_package(output_path: Path) -> None:
📜 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 c5a5301 and ecb34b8.

📒 Files selected for processing (5)
  • pyproject.toml
  • tests/conftest.py
  • tests/main/conftest.py
  • tests/main/openapi/test_main_openapi.py
  • tests/test_input_model.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • pyproject.toml
  • tests/test_input_model.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/conftest.py (1)
scripts/build_cli_docs.py (1)
  • collect_cli_docs (922-933)
tests/main/openapi/test_main_openapi.py (2)
tests/main/conftest.py (2)
  • output_file (99-101)
  • run_main_and_assert (245-409)
tests/test_main_kr.py (1)
  • output_file (44-46)
🪛 Ruff (0.14.10)
tests/main/conftest.py

491-491: 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). (11)
  • GitHub Check: 3.13 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.11 on macOS
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.12 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (12)
tests/main/openapi/test_main_openapi.py (3)

3522-3538: LGTM! New msgspec union operator test is well-structured.

The test correctly validates msgspec.Struct generation without the union operator, using explicit Union[X, Y] syntax instead of the X | Y operator. The test follows established patterns and includes the appropriate @MSGSPEC_LEGACY_BLACK_SKIP decorator.


3541-3557: LGTM! Test complements existing oneOf coverage.

This test appropriately validates msgspec.Struct generation for oneOf schemas containing null types without using the union operator syntax. It provides good coverage alongside the union operator variant at line 3505.


3560-3573: No action needed. The test is correctly without the @MSGSPEC_LEGACY_BLACK_SKIP decorator because its expected output is too simple (a basic Struct with minimal type annotations) to trigger the msgspec.Struct formatting differences that the decorator is designed to skip on Python 3.12 with black < 24.0.0. Unlike the more complex msgspec tests that use Union types or multiple complex fields, the inline const case doesn't generate the formatting issues that would cause test failures without the skip.

tests/main/conftest.py (3)

237-242: LGTM!

The removal of pragma annotations here is consistent with the PR objective of consolidating coverage checks. The code logic remains unchanged.


395-406: LGTM!

The expected file deduction logic is unchanged - the prefix stripping loop correctly exits after the first match.


496-533: LGTM!

The added # pragma: no cover annotations on defensive branches (spec validation, exception handling) are appropriate. These paths are difficult to trigger in normal test execution and represent edge-case safeguards.

tests/conftest.py (6)

103-107: LGTM!

Good documentation practice to explain why the function is excluded from coverage - it clarifies that this code path only executes during the cli-docs tox job.


217-255: LGTM!

The pragma annotations on the collect_cli_docs and validation_errors branches are appropriate - these paths only execute during the --collect-cli-docs mode which runs in a separate tox job.


366-426: LGTM!

The docstring updates consistently explain that these formatting helper functions are only called during assertion failures, which clarifies the # pragma: no cover exclusions.


472-476: LGTM!

Using from None to suppress the exception chain is appropriate here - it prevents the confusing "During handling of the above exception..." message when the FileNotFoundError is an expected condition that's being converted to a more meaningful AssertionError.


312-333: LGTM!

The added config: pytest.Config parameter is properly used to check the --collect-cli-docs option. The noqa: ARG001 comment correctly applies to the unused exitstatus parameter, not config.


478-487: Verify whether _load_value() is the intended public API for ExternalFile objects.

The type branching correctly handles both string and ExternalFile return types from external_file(). However, _load_value() is a private method (underscore prefix), and the intended public API for accessing content from inline-snapshot's ExternalFile should be verified. Consider checking the inline-snapshot library documentation (v0.31.1+) to confirm this is the recommended approach or if a public alternative exists.

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 (2)
tests/main/conftest.py (1)

491-491: Remove unused noqa directive.

The noqa: PLR0912 directive suppresses a rule that is not enabled in your ruff configuration, making it unnecessary.

🔎 Proposed fix
-def _import_package(output_path: Path) -> None:  # noqa: PLR0912
+def _import_package(output_path: Path) -> None:
tests/conftest.py (1)

350-352: Remove unused noqa directive.

The # noqa: PERF203 on line 350 is unnecessary because PERF203 is not enabled. Remove it while keeping the # pragma: no branch.

🔎 Proposed fix
-        except ValueError:  # noqa: PERF203  # pragma: no branch
+        except ValueError:  # pragma: no branch
             continue
📜 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 976b9d2 and 5262f03.

📒 Files selected for processing (4)
  • tests/conftest.py
  • tests/main/conftest.py
  • tests/main/test_public_api_signature_baseline.py
  • tests/test_input_model.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_input_model.py
🧰 Additional context used
🧬 Code graph analysis (2)
tests/conftest.py (2)
scripts/build_cli_docs.py (1)
  • collect_cli_docs (922-933)
src/datamodel_code_generator/__main__.py (1)
  • _normalize_line_endings (763-765)
tests/main/test_public_api_signature_baseline.py (2)
src/datamodel_code_generator/config.py (2)
  • GenerateConfig (66-207)
  • ParserConfig (210-339)
src/datamodel_code_generator/enums.py (2)
  • StrictTypes (233-240)
  • UnionMode (212-216)
🪛 Ruff (0.14.10)
tests/main/conftest.py

491-491: Unused noqa directive (non-enabled: PLR0912)

Remove unused noqa directive

(RUF100)

tests/conftest.py

350-350: Unused noqa directive (non-enabled: PERF203)

Remove unused noqa directive

(RUF100)

tests/main/test_public_api_signature_baseline.py

426-426: Unused noqa directive (non-enabled: PLR0911)

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

348-348: Coverage pragmas are appropriate for this PR scope.

The non-functional coverage annotations (# pragma: no cover and # pragma: no branch) align with the PR objective to adjust coverage thresholds and do not affect runtime behavior.

Also applies to: 426-426, 510-510, 657-657, 682-682, 708-708, 730-730, 736-736


426-426: Remove unused noqa directive.

The # noqa: PLR0911 is unused because the PLR0911 rule ("Too many return statements") is not enabled in your project's Ruff configuration. Either enable the rule if desired or remove the directive.

🔎 Proposed fix
-def _normalize_type(tp: Any) -> str:  # noqa: PLR0911  # pragma: no cover
+def _normalize_type(tp: Any) -> str:  # pragma: no cover
⛔ 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/conftest.py (3)

237-242: Pragma removal aligns with coverage improvements.

The removal of the coverage pragma from the if expected_stdout_path is not None condition is consistent with the PR's objective to increase coverage thresholds. The logic correctly validates that capsys is provided when stdout verification is requested.


395-406: LGTM! Expected filename derivation is correct.

The pragma removal from line 395 aligns with the PR's coverage goals. The logic correctly derives the expected filename from the calling test function's name using frame introspection, stripping known test prefixes.


484-488: Pragma removal supports increased coverage threshold.

The removal of coverage pragmas from the directory validation logic (line 484) and the exec check (line 487) is consistent with the PR's goal. The code correctly handles directory-based output validation and conditionally imports packages for runtime verification.

tests/conftest.py (10)

103-107: LGTM: Coverage pragma correctly applied.

The docstring accurately explains that this validation only runs during CLI docs collection (which doesn't contribute to coverage), and the pragma placement is appropriate.


217-221: LGTM: Proper coverage granularity.

Removing the pragma from the function signature while keeping it on specific branches (lines 235, 250) is the correct approach. The function is always called during collection, but certain branches only execute with --collect-cli-docs.


235-239: LGTM: Branch pragma correctly placed.

This branch only executes during CLI documentation collection, so the coverage pragma is appropriate.


250-255: LGTM: Error path pragma correctly placed.

This block only executes when there are validation errors during CLI doc collection, so the coverage pragma is appropriate.


366-376: LGTM: Docstring accurately describes usage context.

The updated docstring correctly explains that this function is only called during assertion failures, justifying the pragma.


379-383: LGTM: Docstring clarifies assertion-failure context.

The enhanced docstring correctly explains when this formatting function is invoked, justifying the pragma placement.


403-407: LGTM: Docstring clarifies file-not-found context.

The updated docstring correctly explains this function is only called when the expected file doesn't exist, justifying the pragma.


422-426: LGTM: Docstring clarifies diff context.

The updated docstring correctly explains this function is only called when content doesn't match expectations, justifying the pragma.


478-487: Verify the type handling logic for external_file.

The new isinstance(expected, str) check suggests that external_file() can return either a string or an object with a _load_value() method. The else branch (marked with pragma) handles the object case.

Please verify:

  1. Under what conditions does external_file() return a non-string object?
  2. Is the _load_value() method the correct way to extract content from that object?
  3. Should the else branch have test coverage, or is it correctly marked as uncovered?

The logic appears sound, but confirming the type contract with the inline_snapshot library would be prudent.


543-547: LGTM: Branch pragma correctly placed on prefix-stripping loop.

The pragma: no branch is appropriate here because the loop is expected to break when it finds a matching prefix, preventing coverage from requiring the non-existent "complete without break" branch.

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)
tests/main/test_public_api_signature_baseline.py (1)

426-462: Remove unused noqa directive.

The static analysis correctly identifies that # noqa: PLR0911 is unnecessary since PLR0911 (too-many-return-statements) is not enabled in the project's ruff configuration.

Proposed fix
-def _normalize_type(tp: Any) -> str:  # noqa: PLR0911  # pragma: no cover
+def _normalize_type(tp: Any) -> str:  # pragma: no cover
📜 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 5262f03 and 9fec965.

📒 Files selected for processing (3)
  • tests/main/conftest.py
  • tests/main/test_public_api_signature_baseline.py
  • tests/test_input_model.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_input_model.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/main/conftest.py (1)
tests/conftest.py (3)
  • validate_generated_code (703-730)
  • record_exec (299-302)
  • record_error (304-306)
🪛 Ruff (0.14.10)
tests/main/test_public_api_signature_baseline.py

426-426: Unused noqa directive (non-enabled: PLR0911)

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-pydantic1 on Ubuntu
  • GitHub Check: py312-black23 on Ubuntu
  • GitHub Check: 3.10 on Ubuntu
  • GitHub Check: py312-black24 on Ubuntu
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.13 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.13 on Windows
  • GitHub Check: benchmarks
  • GitHub Check: Analyze (python)
🔇 Additional comments (7)
tests/main/conftest.py (5)

237-242: LGTM - Coverage pragma adjustments.

The removal of # pragma: no branch is appropriate since this branch is now being exercised by tests.


395-406: LGTM - Coverage pragma adjustments.

The # pragma: no branch removal on line 395 aligns with the PR objective to consolidate coverage checks. The remaining pragma on line 401 for the prefix loop is appropriate.


484-488: LGTM - Pragma changed from no cover to no branch.

The change from # pragma: no cover to # pragma: no branch on the elif is semantically correct—the directory branch is now covered, but not all sub-branches may be taken in every test run.


536-540: Verify unconditional sys.path.remove() is safe.

The summary indicates this change removes a previous conditional check (if str(parent_directory) in sys.path). The unconditional remove() will raise ValueError if the path is not present.

Reviewing the code flow: sys.path.insert() at line 509 is called at the start of each loop iteration before any operations that could throw, so for each (parent_directory, _) in packages, the path should always be present when the finally block runs. This appears safe, but please confirm no edge cases exist where the insert might be skipped.


491-534: LGTM - Coverage pragmas added to defensive branches.

The added # pragma: no cover markers on:

  • Line 496: The fallback packages discovery path
  • Line 501: Empty packages early return
  • Line 513, 526: Spec/loader None checks
  • Line 533: Exception handler

These are appropriate for defensive code paths that are unlikely to be hit during normal test execution.

tests/main/test_public_api_signature_baseline.py (2)

348-362: LGTM - Coverage pragma added.

Adding # pragma: no cover to _type_to_str is reasonable since this helper may not have all code paths exercised in every test run.


717-725: LGTM - Pragma adjustments for pydantic v2 model_rebuild.

The change from # pragma: no cover to # pragma: no branch on line 717 is appropriate—hasattr(GenerateConfig, "model_rebuild") is always true under pydantic v2, so the branch is covered but the else path doesn't exist. The # pragma: no cover on the ImportError handler (line 723) correctly marks a defensive fallback that won't trigger in normal pydantic v2 environments.

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)
tests/main/test_public_api_signature_baseline.py (1)

426-462: Remove unused noqa directive.

The PLR0911 rule is not enabled in your linter configuration, making this directive unnecessary. The # pragma: no cover annotation is appropriate.

🔎 Proposed fix
-def _normalize_type(tp: Any) -> str:  # noqa: PLR0911  # pragma: no cover
+def _normalize_type(tp: Any) -> str:  # pragma: no cover

Based on static analysis hints.

📜 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 9fec965 and 3f2b713.

📒 Files selected for processing (1)
  • tests/main/test_public_api_signature_baseline.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/main/test_public_api_signature_baseline.py (3)
src/datamodel_code_generator/config.py (1)
  • GenerateConfig (66-207)
tests/data/expected/main/input_model/config_class.py (1)
  • GenerateConfig (117-248)
src/datamodel_code_generator/enums.py (2)
  • StrictTypes (233-240)
  • UnionMode (212-216)
🪛 Ruff (0.14.10)
tests/main/test_public_api_signature_baseline.py

426-426: Unused noqa directive (non-enabled: PLR0911)

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). (14)
  • GitHub Check: py312-isort5 on Ubuntu
  • GitHub Check: 3.10 on Windows
  • GitHub Check: 3.12 on macOS
  • GitHub Check: 3.14 on macOS
  • GitHub Check: py312-black22 on Ubuntu
  • GitHub Check: 3.14 on Windows
  • GitHub Check: 3.12 on Windows
  • GitHub Check: 3.10 on macOS
  • GitHub Check: 3.11 on Windows
  • GitHub Check: 3.13 on macOS
  • GitHub Check: 3.11 on macOS
  • GitHub Check: 3.13 on Windows
  • GitHub Check: Analyze (python)
  • GitHub Check: benchmarks
🔇 Additional comments (6)
tests/main/test_public_api_signature_baseline.py (6)

348-362: LGTM on the pragma addition.

The # pragma: no cover annotation is appropriate for this test utility function.


510-514: LGTM on removing the early skip logic.

Removing the conditional skip for Parameter.empty enables more thorough validation of default values between the baseline and GenerateConfig, improving test coverage.


656-661: LGTM on the stricter validation.

Removing the conditional skip logic ensures all default values are validated for consistency between GenerateConfig and the generate() signature.


672-681: LGTM on the enhanced validation.

The test correctly preserves the callable default handling while removing the Parameter.empty skip, providing better validation coverage.


692-698: LGTM on removing the skip logic.

This change aligns with the pattern of stricter validation across the test suite, ensuring complete default value consistency.


708-716: LGTM on the pragma annotations.

The coverage pragmas are appropriately placed:

  • # pragma: no branch for the hasattr check is correct since one branch is always taken based on Pydantic version
  • # pragma: no cover for the ImportError handler is reasonable as it's a fallback path

@koxudaxi koxudaxi merged commit c1682ac into main Jan 3, 2026
39 of 40 checks passed
@koxudaxi koxudaxi deleted the feature/increase-coverage-threshold branch January 3, 2026 15:34
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 3, 2026

🎉 Released in 0.52.1

This PR is now available in the latest release. See the release notes for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants