Skip to content

๐Ÿ› ๏ธ Development

Install the package in editable mode:

$ git clone [email protected]:koxudaxi/datamodel-code-generator.git
$ pip install -e datamodel-code-generator

๐Ÿค Contribute

We are waiting for your contributions to datamodel-code-generator.

๐Ÿ“ How to contribute

## 1. Clone your fork repository
$ git clone [email protected]:<your username>/datamodel-code-generator.git
$ cd datamodel-code-generator

## 2. Install [uv](https://docs.astral.sh/uv/getting-started/installation/)
$ curl -LsSf https://astral.sh/uv/install.sh | sh

## 3. Install tox with uv
$ uv tool install --python-preference only-managed --python 3.13 tox --with tox-uv

## 4. Create developer environment
$ tox run -e dev

.tox/dev is a Python environment you can use for development purposes

## 5. Install pre-commit hooks
$ uv tool install prek
$ prek install

## 6. Create new branch and rewrite code.
$ git checkout -b new-branch

## 7. Run unittest under Python 3.13 (you should pass all test and coverage should be 100%)
$ tox run -e 3.13

## 8. Format and lint code (will print errors that cannot be automatically fixed)
$ tox run -e fix

## 9. Check README help text is up to date
$ tox run -e readme

## 10. Check CLI documentation is up to date
$ tox run -e cli-docs

## 11. Commit and Push...

๐Ÿงช E2E test assertions

E2E tests that validate generated output must use the shared assertion helpers instead of direct assert statements. The helpers compare complete generated files, generated modules, warnings, errors, and HTTP request behavior with consistent diffs and update hints.

Use helpers such as run_main_and_assert, run_main_url_and_assert, create_assert_file_content, assert_output, assert_directory_content, assert_generated_modules_output, assert_generated_file_matches_output, assert_httpx_get_kwargs, and assert_warnings_contain where they fit. Prefer full expected-file or inline snapshot comparisons for generated output over substring checks.

The file-output helpers use inline-snapshot and external_file() internally. When an expected output file is missing, the failure message includes the command to create it, such as tox run -e <version> -- --inline-snapshot=create. When an existing expected file differs from the generated output, the failure includes a diff and the command to update it, such as tox run -e <version> -- --inline-snapshot=fix. Review the generated files and the resulting git diff before committing. See the inline-snapshot --inline-snapshot pytest options for the meaning of create and fix.

Direct assert statements are blocked in guarded test modules by tests/test_assert_helper_usage.py. New test files are guarded by default; add legacy or unit-focused files to assert_helper_direct_assert_exempt_files in pyproject.toml only when they are intentionally outside the generated-output helper policy. Use @pytest.mark.allow_direct_assert for narrow in-file exceptions that cannot reasonably be expressed with the shared helpers, such as external-request mock checks or intermediate-state checks.

Parser generation state

Parser code must keep generated output, naming order, parse order, and canonical model selection compatible with existing releases. ModelResolver remains the only authority for names. Do not move name generation or parser dispatch into the generation index.

Use GenerationStore for parser-side mutations that affect generation facts:

  • Register parsed models with generation_store.register_model(model).
  • Replace references with generation_store.replace_data_type_ref(...) or generation_store.detach_data_type_ref(...).
  • Replace field or nested data types with replace_field_type(...), replace_nested_data_type(...), or set_nested_data_types(...).
  • Replace fields or base classes with set_fields(...), append_field(...), insert_field(...), remove_field(...), or set_base_classes(...).
  • Move or rename generated models with move_model(...), rename_model(...), or update_model_reference(...).

Parser code should not directly assign data_type.reference, model.fields, model.base_classes, model.reference.name, or call reference child mutation helpers. Read dependency information through GenerationIndex queries instead of using Reference.children as a reverse index.

The local pre-commit hook generation-store-usage runs scripts/check_generation_store_usage.py and rejects common parser mutations that bypass the store. If a new mutation helper is needed, add the method to GENERATION_STORE_MUTATION_METHODS and update the checker tests so contributors get an actionable message.

โž• Adding a New CLI Option

When adding a new CLI option to datamodel-code-generator, follow these steps:

Step 1: Implement the option (Required)

Add the option to src/datamodel_code_generator/arguments.py:

arg_parser.add_argument(
    "--my-new-option",
    help="Description of what this option does",
    action="store_true",  # or other action type
)

Step 2: Add a test with documentation marker (Required)

Create a test that demonstrates the option and add the @pytest.mark.cli_doc() marker:

@pytest.mark.cli_doc(
    options=["--my-new-option"],
    input_schema="jsonschema/example.json",  # Path relative to tests/data/
    cli_args=["--my-new-option"],
    golden_output="jsonschema/example_with_my_option.py",  # Expected output
)
def test_my_new_option(output_file: Path) -> None:
    """Short description of what the option does.

    This docstring becomes the documentation for the option.
    Explain when and why users would use this option.
    """
    run_main_and_assert(
        input_path=JSON_SCHEMA_DATA_PATH / "example.json",
        output_path=output_file,
        extra_args=["--my-new-option"],
        ...
    )

Step 3: Categorize the option (Optional)

By default, new options appear in "General Options". To place in a specific category, add to src/datamodel_code_generator/cli_options.py:

CLI_OPTION_META: dict[str, CLIOptionMeta] = {
    ...
    "--my-new-option": CLIOptionMeta(
        name="--my-new-option",
        category=OptionCategory.MODEL,  # or FIELD, TYPING, TEMPLATE, etc.
    ),
}

Step 4: Generate and verify documentation

# Regenerate CLI docs
$ pytest --collect-cli-docs -p no:xdist -q
$ python scripts/build_cli_docs.py

# Verify docs are correct
$ tox run -e cli-docs

# If you modified config.py, regenerate config TypedDicts
$ tox run -e config-types

๐Ÿ”ง Troubleshooting

If tox run -e cli-docs fails:

  • "No test found documenting option --xxx": Add @pytest.mark.cli_doc(options=["--xxx"], ...) to a test
  • "File not found: ...": Check that input_schema and golden_output paths are correct
  • "CLI docs are OUT OF DATE": Run python scripts/build_cli_docs.py to regenerate

๐Ÿ“– CLI Documentation Marker Reference

The cli_doc marker supports:

Parameter Required Description
options Yes List of CLI options this test documents
input_schema Yes Input schema path (relative to tests/data/)
cli_args Yes CLI arguments used in the test
golden_output Yes* Expected output file path
model_outputs No Dict of model type โ†’ output file (for multi-model tabs)
version_outputs No Dict of Python version โ†’ output file
comparison_output No Baseline output without option (for before/after)
primary No Set True if this is the main example for the option

*Either golden_output or model_outputs is required.

See existing tests in tests/main/ for examples.