Skip to content

Add deprecated decorators for dataclass output#3044

Merged
koxudaxi merged 6 commits intomainfrom
fix/issue-2543-dataclass-deprecated-decorator
Mar 10, 2026
Merged

Add deprecated decorators for dataclass output#3044
koxudaxi merged 6 commits intomainfrom
fix/issue-2543-dataclass-deprecated-decorator

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Mar 10, 2026

Fixes: #2543

Summary by CodeRabbit

  • New Features

    • Generated dataclasses and Pydantic v2 dataclasses now receive a deprecation decorator (e.g., "LegacyUser is deprecated.") when schemas mark models as deprecated; existing decorators are preserved and required deprecation import is included.
  • Tests

    • Added tests covering deprecated model generation for dataclasses and Pydantic v2 dataclasses, including cases with existing or additional decorators.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: df27235a-9250-416a-9936-38f17ca69ae6

📥 Commits

Reviewing files that changed from the base of the PR and between eaf0839 and 8eebfed.

📒 Files selected for processing (3)
  • tests/data/expected/main/jsonschema/deprecated_dataclass_with_other_decorator.py
  • tests/data/expected/main/jsonschema/deprecated_pydantic_v2_dataclass_with_other_decorator.py
  • tests/main/jsonschema/test_main_jsonschema.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/main/jsonschema/test_main_jsonschema.py

📝 Walkthrough

Walkthrough

Propagates JSON Schema "deprecated" metadata into model template data and applies a class-level @deprecated("ClassName is deprecated.") decorator to generated dataclasses (including pydantic v2) when not already present; includes parser changes, tests, and expected outputs.

Changes

Cohort / File(s) Summary
Core Deprecation Support
src/datamodel_code_generator/model/base.py
Adds DataModel._set_deprecated_decorator() to append @deprecated("ClassName is deprecated.") when extra_template_data["deprecated"] is true and no existing @deprecated decorator exists; registers typing_extensions.deprecated in additional imports.
DataClass Integration
src/datamodel_code_generator/model/dataclass.py, src/datamodel_code_generator/model/pydantic_v2/dataclass.py
Calls self._set_deprecated_decorator() in DataClass.__init__ so class-level deprecation is applied during DataClass instantiation for both standard and pydantic v2 dataclasses.
Parser Metadata Propagation
src/datamodel_code_generator/parser/jsonschema.py
Centralizes metadata collection via _set_schema_metadata() and adds set_deprecated(path, obj) usage; updates parsing flows (variant, object/common part, allOf, array, enum) to record deprecated into template metadata and adjusts parse_enum() to accept path.
Tests & Expected Outputs
tests/main/jsonschema/test_main_jsonschema.py, tests/data/expected/main/jsonschema/deprecated_*.py
Adds tests for deprecated-model generation and preservation of existing decorators; adds expected generated files showing @deprecated('LegacyUser is deprecated.') for dataclasses and pydantic v2 dataclasses, including variants with other decorators and imports.

Sequence Diagram

sequenceDiagram
    participant Parser as JSONSchemaParser
    participant Metadata as SchemaMetadata
    participant Factory as ModelFactory
    participant DataClass as DataClass.__init__
    participant Model as DataModel

    Parser->>Metadata: _set_schema_metadata(path, obj)
    Metadata->>Metadata: set_deprecated(path, obj)
    Metadata-->>Parser: record deprecated in extra_template_data
    Parser->>Factory: create model / reference
    Factory->>DataClass: instantiate DataClass(with template data)
    DataClass->>Model: _set_deprecated_decorator()
    Model->>Model: inspect extra_template_data["deprecated"] and decorators
    alt deprecated and no existing decorator
        Model->>Model: append `@deprecated("ClassName is deprecated.")`
        Model->>Model: add `typing_extensions.deprecated` to _additional_imports
    end
    Model-->>Factory: model ready
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • #2746: Overlaps changes to DataClass initialization and JSON Schema parsing paths where deprecation decorators and metadata propagation are handled.

Suggested labels

breaking-change-analyzed

Poem

🐰 Hop, hop—an old class gets a ribbon and sigh,

"LegacyUser is deprecated," I whisper nearby.
I pin a tiny note on the dataclass with care,
So callers will know it's time to beware.

🚥 Pre-merge checks | ✅ 5
✅ 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 directly summarizes the main change: adding deprecated decorator support for dataclass output, which aligns with the PR objectives.
Linked Issues check ✅ Passed The PR fully addresses issue #2543 by generating @deprecated decorators on dataclass definitions when JSON Schema marks types as deprecated, including proper imports from typing_extensions.
Out of Scope Changes check ✅ Passed All changes relate directly to implementing deprecated decorator support: parser logic for metadata, dataclass initialization calls, test cases, and expected output files. No out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 96.55% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-2543-dataclass-deprecated-decorator

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

❤️ Share

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 10, 2026

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 10, 2026

Merging this PR will not alter performance

⚠️ 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.

✅ 11 untouched benchmarks
⏩ 98 skipped benchmarks1


Comparing fix/issue-2543-dataclass-deprecated-decorator (8eebfed) with main (569894a)

Open in CodSpeed

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 10, 2026

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #3044   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           86        86           
  Lines        18045     18071   +26     
  Branches      2098      2101    +3     
=========================================
+ Hits         18045     18071   +26     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

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

3623-3777: ⚠️ Potential issue | 🟡 Minor

Move _set_schema_metadata() above the non-nullable enum early return.

Line 3774 returns before metadata is recorded, so ordinary enums never get the new deprecated flag in extra_template_data. Only the nullable-wrapper enum path hits the new metadata flow.

💡 Proposed fix
         reference = self.model_resolver.add(
             path,
             name,
             class_name=True,
             singular_name=singular_name,
             singular_name_suffix="Enum",
             loaded=True,
             model_type="enum",
         )
+        self._set_schema_metadata(reference.path, obj)
+        self.set_schema_extensions(reference.path, obj)
 
         if not nullable:
             return create_enum(reference)
-
-        self._set_schema_metadata(reference.path, obj)
-        self.set_schema_extensions(reference.path, obj)
         enum_reference = self.model_resolver.add(
             [*path, "Enum"],
             f"{reference.name}Enum",
             class_name=True,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/datamodel_code_generator/parser/jsonschema.py` around lines 3623 - 3777,
The parse_enum path returns early for non-nullable enums before recording schema
metadata, so move the metadata calls above that return: inside parse_enum, call
self._set_schema_metadata(reference.path, obj) and
self.set_schema_extensions(reference.path, obj) immediately after creating the
Reference (the reference variable produced by self.model_resolver.add) and
before the line that currently does "return create_enum(reference)"; this
ensures both the non-nullable branch and the nullable-wrapper branch record
deprecated/extra_template_data consistently (references: parse_enum,
create_enum, _set_schema_metadata, set_schema_extensions, model_resolver.add).
🧹 Nitpick comments (1)
tests/model/pydantic_v2/test_dataclass.py (1)

136-151: LGTM!

The test correctly verifies the deprecated decorator functionality for Pydantic v2 dataclasses, mirroring the test in the standard dataclass module.

Consider adding a test for existing decorator preservation.

The standard dataclass tests include test_dataclass_preserves_existing_deprecated_decorator to verify no decorator duplication. For consistency and complete coverage of the Pydantic v2 dataclass path, consider adding a similar test here.

,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/model/pydantic_v2/test_dataclass.py` around lines 136 - 151, Add a new
test (e.g., test_data_class_preserves_existing_deprecated_decorator) alongside
test_data_class_with_deprecated_decorator that constructs a DataClass (using
DataModelFieldBase, DataType, Reference) but simulates an already-present
deprecated decorator in the template data (e.g., include a pre-existing
decorator string in extra_template_data for "test_model"); render the DataClass
and assert the deprecated decorator appears only once in rendered output and
that the typing_extensions import for "deprecated" is not duplicated (check
data_class.imports) to ensure existing decorators are preserved rather than
duplicated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/datamodel_code_generator/model/base.py`:
- Around line 742-750: The code mutates a caller-owned list because
self.decorators aliases the input from DataModel.__init__, so
_set_deprecated_decorator should not append in-place; instead create a new list
and reassign it (e.g., set self.decorators = list(self.decorators) + [f"..."] or
construct a new list and assign) when adding the deprecated decorator in
_set_deprecated_decorator, leaving the original caller list unchanged; keep
adding the import to self._additional_imports as before.

---

Outside diff comments:
In `@src/datamodel_code_generator/parser/jsonschema.py`:
- Around line 3623-3777: The parse_enum path returns early for non-nullable
enums before recording schema metadata, so move the metadata calls above that
return: inside parse_enum, call self._set_schema_metadata(reference.path, obj)
and self.set_schema_extensions(reference.path, obj) immediately after creating
the Reference (the reference variable produced by self.model_resolver.add) and
before the line that currently does "return create_enum(reference)"; this
ensures both the non-nullable branch and the nullable-wrapper branch record
deprecated/extra_template_data consistently (references: parse_enum,
create_enum, _set_schema_metadata, set_schema_extensions, model_resolver.add).

---

Nitpick comments:
In `@tests/model/pydantic_v2/test_dataclass.py`:
- Around line 136-151: Add a new test (e.g.,
test_data_class_preserves_existing_deprecated_decorator) alongside
test_data_class_with_deprecated_decorator that constructs a DataClass (using
DataModelFieldBase, DataType, Reference) but simulates an already-present
deprecated decorator in the template data (e.g., include a pre-existing
decorator string in extra_template_data for "test_model"); render the DataClass
and assert the deprecated decorator appears only once in rendered output and
that the typing_extensions import for "deprecated" is not duplicated (check
data_class.imports) to ensure existing decorators are preserved rather than
duplicated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9b77c985-ec73-45be-bc39-f6dd579abab0

📥 Commits

Reviewing files that changed from the base of the PR and between 95daa4e and d27a2b1.

⛔ Files ignored due to path filters (1)
  • tests/data/jsonschema/deprecated_dataclass.json is excluded by !tests/data/**/*.json and included by none
📒 Files selected for processing (8)
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/model/dataclass.py
  • src/datamodel_code_generator/model/pydantic_v2/dataclass.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • tests/data/expected/main/jsonschema/deprecated_dataclass.py
  • tests/main/jsonschema/test_main_jsonschema.py
  • tests/model/dataclass/test_param.py
  • tests/model/pydantic_v2/test_dataclass.py

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/datamodel_code_generator/model/base.py`:
- Around line 742-750: The _set_deprecated_decorator method currently returns
early if a "@deprecated" decorator already exists, which prevents adding the
required import; update _set_deprecated_decorator so that when
extra_template_data.get("deprecated") is true you always append
Import.from_full_path("typing_extensions.deprecated") to
self._additional_imports (regardless of the early-return path), and only skip
adding the decorator string to self.decorators if one already exists; reference
_set_deprecated_decorator, self.decorators, self._additional_imports,
Import.from_full_path("typing_extensions.deprecated") and self.class_name to
locate the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ba1f0f2-d67f-4263-bb84-55b067386ecb

📥 Commits

Reviewing files that changed from the base of the PR and between d27a2b1 and 0213d81.

📒 Files selected for processing (4)
  • src/datamodel_code_generator/model/base.py
  • src/datamodel_code_generator/parser/jsonschema.py
  • tests/data/expected/main/jsonschema/deprecated_pydantic_v2_dataclass.py
  • tests/main/jsonschema/test_main_jsonschema.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/main/jsonschema/test_main_jsonschema.py

Comment thread src/datamodel_code_generator/model/base.py
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/main/jsonschema/test_main_jsonschema.py`:
- Around line 3978-3992: Add a second test alongside
test_main_dataclass_deprecated_model_preserves_existing_decorator that verifies
the generator will add the deprecated decorator and import when a different
pre-existing decorator is present: copy the existing test pattern using
run_main_and_assert with input_path "deprecated_dataclass.json", keep
"--output-model-type" and use "--class-decorators" to pass a non-deprecated
decorator (e.g., "@some_decorator"), and assert against a new expected output
file that contains both the original decorator and the added `@deprecated`
import/annotation; name the new test to indicate it covers the non-@deprecated
existing-decorator case and use the same assert_file_content helper.
- Around line 3995-4004: Add a new test that mirrors the "already has
decorators" regression case for the pydantic_v2.dataclass backend: create a test
function alongside test_main_pydantic_v2_dataclass_deprecated_model (e.g.,
test_main_pydantic_v2_dataclass_deprecated_model_with_existing_decorators) that
calls run_main_and_assert with input_path=JSON_SCHEMA_DATA_PATH /
"deprecated_dataclass_with_decorators.json" (or the equivalent
existing-decorated input), output_path=output_file,
input_file_type="jsonschema", assert_func=assert_file_content, expected_file set
to the decorated-expected fixture (matching the pattern used for the other
dataclass backend), and
extra_args=["--output-model-type","pydantic_v2.dataclass"]; ensure the test uses
the same decorated fixture names and assertion helper as the existing-decorator
case so decorator/import handling is covered for pydantic_v2.dataclass.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 23c46f5e-f353-4cbd-b6a4-6ce60fdec939

📥 Commits

Reviewing files that changed from the base of the PR and between 0213d81 and b10c6c8.

📒 Files selected for processing (2)
  • src/datamodel_code_generator/model/base.py
  • tests/main/jsonschema/test_main_jsonschema.py

Comment thread tests/main/jsonschema/test_main_jsonschema.py
Comment thread tests/main/jsonschema/test_main_jsonschema.py
@koxudaxi koxudaxi merged commit f3f3912 into main Mar 10, 2026
36 checks passed
@koxudaxi koxudaxi deleted the fix/issue-2543-dataclass-deprecated-decorator branch March 10, 2026 18:53
@github-actions
Copy link
Copy Markdown
Contributor

Breaking Change Analysis

Result: No breaking changes detected

Reasoning: This PR is an additive feature that implements JSON Schema deprecated keyword support for dataclasses. It only affects schemas with explicit deprecated: true, produces valid functional code, doesn't modify templates, and doesn't change CLI/API interfaces. Users who mark schemas as deprecated presumably want deprecation decorators on their generated classes. The generated code remains valid and functional - it just now correctly reflects the schema's deprecation intent.


This analysis was performed by Claude Code Action

@github-actions
Copy link
Copy Markdown
Contributor

🎉 Released in 0.55.0

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate "deprecated" notations for JSON schemas and dataclass output

1 participant