Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/cli-reference/typing-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -2736,6 +2736,25 @@ The `--type-mappings` flag configures the code generation behavior.

Replace schema model types with custom Python types via JSON mapping.

This option is useful for importing models from external libraries (like `geojson-pydantic`)
instead of generating them.

**Override Formats:**

| Format | Description |
|--------|-------------|
| `{"ModelName": "package.Type"}` | Model-level: Skip generating `ModelName` and import from `package` |
| `{"Model.field": "package.Type"}` | Scoped: Override only specific field in specific model |

**Common Use Cases:**

| Use Case | Example Override |
|----------|------------------|
| GeoJSON types | `{"Feature": "geojson_pydantic.Feature"}` |
| Custom datetime | `{"Timestamp": "pendulum.DateTime"}` |
| MongoDB ObjectId | `{"ObjectId": "bson.ObjectId"}` |
| Custom validators | `{"Email": "my_app.types.ValidatedEmail"}` |

!!! tip "Usage"

```bash
Expand All @@ -2744,6 +2763,11 @@ Replace schema model types with custom Python types via JSON mapping.

1. :material-arrow-left: `--type-overrides` - the option documented here

!!! note "Model-level overrides skip generation"
When you specify a model-level override (without a dot in the key), the generator will
**skip generating that model entirely** and import it from the specified package instead.


??? example "Examples"

**Input Schema:**
Expand Down
20 changes: 20 additions & 0 deletions tests/data/expected/main/type_overrides_external_lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# generated by datamodel-codegen:
# filename: type_overrides_external_lib.json
# timestamp: 1985-10-26T08:21:00+00:00

from __future__ import annotations

from typing import Any

from geojson_pydantic import Feature, FeatureCollection
from pydantic import BaseModel


class Model(BaseModel):
__root__: Any


class Place(BaseModel):
name: str | None = None
location: Feature | None = None
boundary: FeatureCollection | None = None
30 changes: 30 additions & 0 deletions tests/data/jsonschema/type_overrides_external_lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Feature": {
"type": "object",
"properties": {
"type": {"type": "string"},
"geometry": {"type": "object"}
}
},
"FeatureCollection": {
"type": "object",
"properties": {
"type": {"type": "string"},
"features": {
"type": "array",
"items": {"$ref": "#/definitions/Feature"}
}
}
},
"Place": {
"type": "object",
"properties": {
"name": {"type": "string"},
"location": {"$ref": "#/definitions/Feature"},
"boundary": {"$ref": "#/definitions/FeatureCollection"}
}
}
}
}
51 changes: 50 additions & 1 deletion tests/main/test_main_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,31 @@ def test_dataclass_arguments_invalid(json_str: str, match: str) -> None:

@pytest.mark.cli_doc(
options=["--type-overrides"],
option_description="""Replace schema model types with custom Python types via JSON mapping.""",
option_description="""Replace schema model types with custom Python types via JSON mapping.

This option is useful for importing models from external libraries (like `geojson-pydantic`)
instead of generating them.

**Override Formats:**

| Format | Description |
|--------|-------------|
| `{"ModelName": "package.Type"}` | Model-level: Skip generating `ModelName` and import from `package` |
| `{"Model.field": "package.Type"}` | Scoped: Override only specific field in specific model |

!!! note "Model-level overrides skip generation"
When you specify a model-level override (without a dot in the key), the generator will
**skip generating that model entirely** and import it from the specified package instead.

**Common Use Cases:**

| Use Case | Example Override |
|----------|------------------|
| GeoJSON types | `{"Feature": "geojson_pydantic.Feature"}` |
| Custom datetime | `{"Timestamp": "pendulum.DateTime"}` |
| MongoDB ObjectId | `{"ObjectId": "bson.ObjectId"}` |
| Custom validators | `{"Email": "my_app.types.ValidatedEmail"}` |
""",
input_schema="jsonschema/type_overrides_test.json",
cli_args=["--type-overrides", '{"CustomType": "my_app.types.CustomType"}'],
golden_output="main/type_overrides_model_level.py",
Expand All @@ -695,6 +719,31 @@ def test_type_overrides_model_level(output_file: Path) -> None:
)


@pytest.mark.cli_doc(
options=["--type-overrides"],
option_description="""Replace schema model types with custom Python types via JSON mapping.""",
input_schema="jsonschema/type_overrides_external_lib.json",
cli_args=[
"--type-overrides",
'{"Feature": "geojson_pydantic.Feature", "FeatureCollection": "geojson_pydantic.FeatureCollection"}',
],
golden_output="main/type_overrides_external_lib.py",
)
@freeze_time(TIMESTAMP)
def test_type_overrides_external_lib(output_file: Path) -> None:
"""Test --type-overrides with external library types like geojson-pydantic."""
run_main_and_assert(
input_path=JSON_SCHEMA_DATA_PATH / "type_overrides_external_lib.json",
output_path=output_file,
input_file_type="jsonschema",
assert_func=assert_file_content,
extra_args=[
"--type-overrides",
'{"Feature": "geojson_pydantic.Feature", "FeatureCollection": "geojson_pydantic.FeatureCollection"}',
],
)


@freeze_time(TIMESTAMP)
def test_type_overrides_scoped(output_file: Path) -> None:
"""Test --type-overrides with scoped override replaces specific field only."""
Expand Down
Loading