Skip to content

Support JSON files for mapping options#3071

Merged
koxudaxi merged 11 commits intomainfrom
fix/issue-3068-json-file-maps
Apr 4, 2026
Merged

Support JSON files for mapping options#3071
koxudaxi merged 11 commits intomainfrom
fix/issue-3068-json-file-maps

Conversation

@koxudaxi
Copy link
Copy Markdown
Owner

@koxudaxi koxudaxi commented Apr 4, 2026

fixes: #3068

Summary by CodeRabbit

  • New Features

    • CLI options now accept JSON mappings via filesystem paths in addition to inline JSON strings.
  • Documentation

    • CLI reference clarified that JSON configuration may be provided inline or as an external JSON file.
  • Tests

    • Added tests for file-based JSON mapping and for error handling on invalid, unreadable, or non-object JSON inputs.
  • Bug Fixes

    • Improved CLI validation and clearer error messages for malformed or non-object JSON.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 4, 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
📝 Walkthrough

Walkthrough

CLI options --base-class-map and --enum-field-as-literal-map now accept either an inline JSON string or a filesystem path to a JSON file. A private helper parses file-backed or inline JSON, enforces object (dict) results, and updates docs and tests for success and failure cases.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/cli-reference/model-customization.md, docs/cli-reference/typing-customization.md
Help text clarified to state each option accepts either inline JSON or a filesystem path to a JSON file.
Argument Parser Implementation
src/datamodel_code_generator/arguments.py
Added private _json_value_or_file(value: str) to accept a file path or raw JSON string, read files with DEFAULT_ENCODING, parse via json.loads, validate the result is a dict, and raise ArgumentTypeError with targeted messages. Wired --base-class-map and --enum-field-as-literal-map to use this helper.
Test Coverage
tests/main/jsonschema/test_main_jsonschema.py
Added positive tests for loading mappings from temporary JSON files and negative tests for invalid JSON, unreadable/invalidly encoded files, and non-object JSON values asserting exit code 2 with specific stderr messages.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as "CLI"
    participant ArgParse as "Argument Parser\n(_json_value_or_file)"
    participant FS as "Filesystem"
    participant JSON as "JSON Parser"
    participant Error as "Error Handler"

    CLI->>ArgParse: receive --base-class-map / --enum-field-as-literal-map value
    alt value is path to existing file
        ArgParse->>FS: read file (DEFAULT_ENCODING)
        FS-->>ArgParse: file contents / read error
        alt read success
            ArgParse->>JSON: json.loads(file contents)
            JSON-->>ArgParse: parsed value / JSON error
        else read error
            ArgParse->>Error: raise ArgumentTypeError("Unable to read JSON file: ...")
        end
    else value is inline JSON
        ArgParse->>JSON: json.loads(value)
        JSON-->>ArgParse: parsed value / JSON error
    end
    alt parsed value is object (dict)
        ArgParse-->>CLI: accept mapping dict
    else not an object
        ArgParse->>Error: raise ArgumentTypeError("Expected a JSON object")
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibble paths and strings with care,
Files or inline — both hop in the air.
Parsers cheer, errors kept light,
Maps now accepted day or night.
Hooray — JSON routes both fair! 🎋

🚥 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 clearly summarizes the main change: adding support for JSON files as input for mapping options, matching the primary objective from issue #3068.
Linked Issues check ✅ Passed The pull request fully addresses issue #3068 by implementing file-path support for --base-class-map and --enum-field-as-literal-map options, with comprehensive tests covering both file and inline JSON inputs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the stated objective: adding JSON file support for mapping options. Documentation, implementation, and test coverage are all aligned with issue #3068 requirements.
Docstring Coverage ✅ Passed Docstring coverage is 88.24% 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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-3068-json-file-maps

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

❤️ Share

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

Generated by GitHub Actions
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

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

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Apr 4, 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-3068-json-file-maps (990893f) with main (5a8cd0d)

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 Apr 4, 2026

Codecov Report

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

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #3071   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           87        87           
  Lines        18185     18237   +52     
  Branches      2085      2087    +2     
=========================================
+ Hits         18185     18237   +52     
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

🧹 Nitpick comments (2)
tests/main/jsonschema/test_main_jsonschema.py (1)

3015-3030: Consider adding failure-path parity for --base-class-map file input.

Line 3015 adds happy-path coverage, but unlike --enum-field-as-literal-map, there’s no invalid JSON / unreadable encoding test for --base-class-map. Adding those would keep both options equally protected.

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

In `@tests/main/jsonschema/test_main_jsonschema.py` around lines 3015 - 3030, Add
failure-path tests for the --base-class-map option similar to the existing tests
for --enum-field-as-literal-map: create two new tests (e.g.,
test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_unreadable_encoding) that use
run_main_and_assert (and the existing error/assert helper used by enum tests) to
assert proper failure when mapping_path contains invalid JSON and when the file
cannot be read with the expected encoding; reference the existing
test_main_jsonschema_base_class_map_from_file, the --base-class-map flag, and
helpers run_main_and_assert / assert_file_content to mirror the happy-path
structure but assert error conditions.
docs/cli-reference/typing-customization.md (1)

1538-1539: Consider adding a file-path example in the usage block.

Since Line 1538 introduces file input support, adding a second usage example (e.g., --enum-field-as-literal-map ./enum-map.json) would make this easier to discover quickly.

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

In `@docs/cli-reference/typing-customization.md` around lines 1538 - 1539, Add a
second usage example to the CLI usage block showing file-path input for the
--enum-field-as-literal-map flag (e.g., `--enum-field-as-literal-map
./enum-map.json`) so readers can discover file-based mapping quickly; place this
alongside the existing inline JSON example and mirror formatting/style used for
other usage examples in the document.
🤖 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/arguments.py`:
- Around line 88-103: The _json_value_or_file function must validate that the
parsed JSON is a dict (mapping) because callers like the base-class-map and
enum-field-as-literal-map expect dict operations; after loading/parsing JSON,
check isinstance(result, dict) and if not raise ArgumentTypeError with a clear
message (e.g., "expected a JSON object/dict for …"); also update the function
return annotation from object to dict to reflect the correct type.

---

Nitpick comments:
In `@docs/cli-reference/typing-customization.md`:
- Around line 1538-1539: Add a second usage example to the CLI usage block
showing file-path input for the --enum-field-as-literal-map flag (e.g.,
`--enum-field-as-literal-map ./enum-map.json`) so readers can discover
file-based mapping quickly; place this alongside the existing inline JSON
example and mirror formatting/style used for other usage examples in the
document.

In `@tests/main/jsonschema/test_main_jsonschema.py`:
- Around line 3015-3030: Add failure-path tests for the --base-class-map option
similar to the existing tests for --enum-field-as-literal-map: create two new
tests (e.g., test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_unreadable_encoding) that use
run_main_and_assert (and the existing error/assert helper used by enum tests) to
assert proper failure when mapping_path contains invalid JSON and when the file
cannot be read with the expected encoding; reference the existing
test_main_jsonschema_base_class_map_from_file, the --base-class-map flag, and
helpers run_main_and_assert / assert_file_content to mirror the happy-path
structure but assert error conditions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: eaf9fe01-ddb6-4cef-9a51-c42ae7ed552b

📥 Commits

Reviewing files that changed from the base of the PR and between 5a8cd0d and ee8d6e8.

⛔ Files ignored due to path filters (1)
  • docs/llms-full.txt is excluded by none and included by none
📒 Files selected for processing (4)
  • docs/cli-reference/model-customization.md
  • docs/cli-reference/typing-customization.md
  • src/datamodel_code_generator/arguments.py
  • tests/main/jsonschema/test_main_jsonschema.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

🧹 Nitpick comments (1)
tests/main/jsonschema/test_main_jsonschema.py (1)

3032-3074: Consider parameterizing duplicated invalid-file-path tests.

The invalid JSON / invalid encoding cases are duplicated for both options; a small parametrized helper would keep future message/behavior updates in one place.

Also applies to: 4670-4706

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

In `@tests/main/jsonschema/test_main_jsonschema.py` around lines 3032 - 3074,
Replace the two nearly identical tests
test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_invalid_encoding with a single
pytest.mark.parametrize test that iterates over tuples of (file_bytes_or_text,
write_method, expected_error_substring) and writes the mapping file accordingly,
then calls run_main_with_args(...) and asserts the SystemExit code and
captured.err contains expected_error_substring; reuse the same
parameters/approach for the duplicate set of tests noted elsewhere, and
reference the existing helper run_main_with_args, JSON_SCHEMA_DATA_PATH, and the
"--base-class-map" flag to locate the call sites to consolidate.
🤖 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 4670-4706: Add a parity test that ensures the CLI rejects
non-object inline JSON passed to --enum-field-as-literal-map: create a new test
(e.g. test_main_enum_field_as_literal_map_non_object_inline_json) in
tests/main/jsonschema/test_main_jsonschema.py that calls run_main_with_args
using --enum-field-as-literal-map with an inline JSON value that is not an
object (for example "[]" or "1"), wrap the call with pytest.raises(SystemExit)
and assert exc_info.value.code == 2, then capture stderr and assert it contains
the expected error text indicating the JSON must be an object (mirroring the
existing base-class-map non-object inline JSON test logic but using the
--enum-field-as-literal-map option and the run_main_with_args helper).

---

Nitpick comments:
In `@tests/main/jsonschema/test_main_jsonschema.py`:
- Around line 3032-3074: Replace the two nearly identical tests
test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_invalid_encoding with a single
pytest.mark.parametrize test that iterates over tuples of (file_bytes_or_text,
write_method, expected_error_substring) and writes the mapping file accordingly,
then calls run_main_with_args(...) and asserts the SystemExit code and
captured.err contains expected_error_substring; reuse the same
parameters/approach for the duplicate set of tests noted elsewhere, and
reference the existing helper run_main_with_args, JSON_SCHEMA_DATA_PATH, and the
"--base-class-map" flag to locate the call sites to consolidate.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dd974f76-748c-4b2e-bafc-91a250460228

📥 Commits

Reviewing files that changed from the base of the PR and between 884636d and 831b5b8.

📒 Files selected for processing (1)
  • tests/main/jsonschema/test_main_jsonschema.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.

🧹 Nitpick comments (1)
tests/main/jsonschema/test_main_jsonschema.py (1)

3032-3074: Consider parameterizing the duplicated error-path tests for both map flags.

The failure-case structures are nearly identical; a small parameterized helper would reduce maintenance overhead.

Also applies to: 4670-4724

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

In `@tests/main/jsonschema/test_main_jsonschema.py` around lines 3032 - 3074, The
two tests test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_invalid_encoding duplicate the
same failure-path logic for the --base-class-map flag; refactor by
parameterizing over the map flags (e.g., "--base-class-map" and the other map
flag used elsewhere) using pytest.mark.parametrize or extracting a small helper
function that accepts the flag name, writes the invalid file (or bytes), calls
run_main_with_args and asserts SystemExit and the expected stderr text; update
or add a single parametric test that iterates the two flags and the two invalid
cases (invalid JSON text and invalid encoding) to replace the duplicated tests
referenced (also apply same change to the similar block at lines 4670-4724).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/main/jsonschema/test_main_jsonschema.py`:
- Around line 3032-3074: The two tests
test_main_jsonschema_base_class_map_from_file_invalid_json and
test_main_jsonschema_base_class_map_from_file_invalid_encoding duplicate the
same failure-path logic for the --base-class-map flag; refactor by
parameterizing over the map flags (e.g., "--base-class-map" and the other map
flag used elsewhere) using pytest.mark.parametrize or extracting a small helper
function that accepts the flag name, writes the invalid file (or bytes), calls
run_main_with_args and asserts SystemExit and the expected stderr text; update
or add a single parametric test that iterates the two flags and the two invalid
cases (invalid JSON text and invalid encoding) to replace the duplicated tests
referenced (also apply same change to the similar block at lines 4670-4724).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a0226c23-cc06-405c-b68b-a27ac374d787

📥 Commits

Reviewing files that changed from the base of the PR and between 831b5b8 and d04179f.

📒 Files selected for processing (1)
  • tests/main/jsonschema/test_main_jsonschema.py

@koxudaxi koxudaxi merged commit 7d41fef into main Apr 4, 2026
39 checks passed
@koxudaxi koxudaxi deleted the fix/issue-3068-json-file-maps branch April 4, 2026 09:07
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

Breaking Change Analysis

Result: Breaking changes detected

Reasoning: This PR contains multiple breaking changes beyond its stated scope of "JSON files for mapping options": (1) Major code generation output changes where default_factory lambdas are replaced with validate_default=True pattern across many test expected files, (2) Jinja2 template structural changes requiring custom template updates, (3) Removed public Python API classes (WrappedDefault, ValidatedDefault) and class variables, (4) Changed error handling from raw httpx exceptions to new SchemaFetchError, and (5) New deprecation warning for remote $ref fetching without explicit opt-in.

Content for Release Notes

Code Generation Changes

  • Default values for model-referencing fields now use validate_default=True instead of default_factory lambdas - Fields with structured defaults (dicts, lists, or scalars referencing Pydantic models/RootModels) previously generated default_factory=lambda: ModelName.model_validate(value) or default_factory=lambda: ModelName(value). They now generate Field(value, validate_default=True), producing simpler but different output. Empty collection defaults changed from default_factory=list/default_factory=dict to Field([], validate_default=True)/Field({}, validate_default=True). Users who regenerate code will see different output. (Support JSON files for mapping options #3071)

    Before:

    count: CountType | None = Field(default_factory=lambda: CountType(10))
    items: dict[str, Item] | None = Field(default_factory=dict, title='Items')

    After:

    count: CountType | None = Field(10, validate_default=True)
    items: dict[str, Item] | None = Field({}, title='Items', validate_default=True)

Custom Template Update Required

  • Type alias Jinja2 templates now require fields guard and base_class fallback - The built-in templates TypeAliasAnnotation.jinja2, TypeAliasType.jinja2, TypeStatement.jinja2, and their Union variants now wrap field access in {%- if fields %}...{%- else %} blocks with a base_class fallback for empty field lists. Users with custom templates derived from the old versions will need to add similar guards. (Support JSON files for mapping options #3071)

API/CLI Changes

  • Removed WrappedDefault, ValidatedDefault classes and SUPPORTS_WRAPPED_DEFAULT, SUPPORTS_VALIDATED_DEFAULT class variables - The WrappedDefault and ValidatedDefault classes from datamodel_code_generator.model._types (re-exported via datamodel_code_generator.model.base) have been deleted. The DataModel class variables SUPPORTS_WRAPPED_DEFAULT and SUPPORTS_VALIDATED_DEFAULT have also been removed. Code that imports or references these will break. (Support JSON files for mapping options #3071)

Error Handling Changes

  • HTTP fetch errors now raise SchemaFetchError instead of raw httpx exceptions - The get_body() function in http.py now catches HTTP errors and raises SchemaFetchError (a new Error subclass) for HTTP status >= 400, network failures, and unexpected HTML responses. Code that caught raw httpx exceptions from remote schema fetching will need to catch SchemaFetchError instead. (Support JSON files for mapping options #3071)
  • Remote $ref fetching now emits FutureWarning without --allow-remote-refs - Fetching remote HTTP/HTTPS $ref references without explicitly passing --allow-remote-refs now emits a FutureWarning deprecation warning. In a future version, remote fetching will be disabled by default. Users relying on implicit remote ref fetching should add --allow-remote-refs to suppress the warning. (Support JSON files for mapping options #3071)

This analysis was performed by Claude Code Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 4, 2026

🎉 Released in 0.56.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.

Allow us to specify JSON file to parameters that might be complicated

1 participant