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
72 changes: 72 additions & 0 deletions docs/cli-reference/base-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
| [`--input-model`](#input-model) | Import a Python type or dict schema from a module. |
| [`--input-model-ref-strategy`](#input-model-ref-strategy) | Strategy for referenced types when using --input-model. |
| [`--output`](#output) | Specify the destination path for generated Python code. |
| [`--schema-version`](#schema-version) | Schema version to use for parsing. |
| [`--schema-version-mode`](#schema-version-mode) | Schema version validation mode. |
| [`--url`](#url) | Fetch schema from URL with custom HTTP headers. |

---
Expand Down Expand Up @@ -326,6 +328,76 @@ is written to stdout.

---

## `--schema-version` {#schema-version}

Schema version to use for parsing.

The `--schema-version` option specifies the schema version to use instead of auto-detection.
Valid values depend on input type: JsonSchema (draft-04, draft-06, draft-07, 2019-09, 2020-12)
or OpenAPI (3.0, 3.1). Default is 'auto' (detected from $schema or openapi field).

!!! tip "Usage"

```bash
datamodel-codegen --input schema.json --schema-version draft-07 # (1)!
```

1. :material-arrow-left: `--schema-version` - the option documented here

??? example "Examples"

**Input Schema:**

```json
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {"s": {"type": ["string"]}},
"required": ["s"]
}
```

**Output:**

> **Error:** File not found: jsonschema/simple_string.py

---

## `--schema-version-mode` {#schema-version-mode}

Schema version validation mode.

The `--schema-version-mode` option controls how schema version validation is performed.
'lenient' (default): accept all features regardless of version.
'strict': warn on features outside the declared/detected version.

!!! tip "Usage"

```bash
datamodel-codegen --input schema.json --schema-version-mode lenient # (1)!
```

1. :material-arrow-left: `--schema-version-mode` - the option documented here

??? example "Examples"

**Input Schema:**

```json
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {"s": {"type": ["string"]}},
"required": ["s"]
}
```

**Output:**

> **Error:** File not found: jsonschema/simple_string.py

---

## `--url` {#url}

Fetch schema from URL with custom HTTP headers.
Expand Down
4 changes: 3 additions & 1 deletion docs/cli-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This documentation is auto-generated from test cases.

| Category | Options | Description |
|----------|---------|-------------|
| 📁 [Base Options](base-options.md) | 7 | Input/output configuration |
| 📁 [Base Options](base-options.md) | 9 | Input/output configuration |
| 🔧 [Typing Customization](typing-customization.md) | 27 | Type annotation and import behavior |
| 🏷️ [Field Customization](field-customization.md) | 24 | Field naming and docstring behavior |
| 🏗️ [Model Customization](model-customization.md) | 39 | Model generation behavior |
Expand Down Expand Up @@ -161,6 +161,8 @@ This documentation is auto-generated from test cases.

### S {#s}

- [`--schema-version`](base-options.md#schema-version)
- [`--schema-version-mode`](base-options.md#schema-version-mode)
- [`--set-default-enum-member`](field-customization.md#set-default-enum-member)
- [`--shared-module-name`](general-options.md#shared-module-name)
- [`--skip-root-model`](model-customization.md#skip-root-model)
Expand Down
4 changes: 4 additions & 0 deletions docs/cli-reference/quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ datamodel-codegen [OPTIONS]
| [`--input-model`](base-options.md#input-model) | Import a Python type or dict schema from a module. |
| [`--input-model-ref-strategy`](base-options.md#input-model-ref-strategy) | Strategy for referenced types when using --input-model. |
| [`--output`](base-options.md#output) | Specify the destination path for generated Python code. |
| [`--schema-version`](base-options.md#schema-version) | Schema version to use for parsing. |
| [`--schema-version-mode`](base-options.md#schema-version-mode) | Schema version validation mode. |
| [`--url`](base-options.md#url) | Fetch schema from URL with custom HTTP headers. |

### 🔧 Typing Customization
Expand Down Expand Up @@ -299,6 +301,8 @@ All options sorted alphabetically:
- [`--remove-special-field-name-prefix`](field-customization.md#remove-special-field-name-prefix) - Remove the special prefix from field names.
- [`--reuse-model`](model-customization.md#reuse-model) - Reuse identical model definitions instead of generating dupl...
- [`--reuse-scope`](model-customization.md#reuse-scope) - Scope for model reuse detection (root or tree).
- [`--schema-version`](base-options.md#schema-version) - Schema version to use for parsing.
- [`--schema-version-mode`](base-options.md#schema-version-mode) - Schema version validation mode.
- [`--set-default-enum-member`](field-customization.md#set-default-enum-member) - Set the first enum member as the default value for enum fiel...
- [`--shared-module-name`](general-options.md#shared-module-name) - Customize the name of the shared module for deduplicated mod...
- [`--skip-root-model`](model-customization.md#skip-root-model) - Skip generation of root model when schema contains nested de...
Expand Down
41 changes: 38 additions & 3 deletions src/datamodel_code_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@
from datamodel_code_generator.parser import DefaultPutDict, LiteralType

if TYPE_CHECKING:
from datamodel_code_generator._types import GraphQLParserConfigDict, OpenAPIParserConfigDict, ParserConfigDict
from datamodel_code_generator._types import (
GraphQLParserConfigDict,
JSONSchemaParserConfigDict,
OpenAPIParserConfigDict,
ParserConfigDict,
)
from datamodel_code_generator._types.generate_config_dict import GenerateConfigDict
from datamodel_code_generator.config import GenerateConfig, ParserConfig

Expand Down Expand Up @@ -456,7 +461,10 @@ def _build_module_content(
def _create_parser_config(
config_class: type[_ConfigT],
generate_config: GenerateConfig,
additional_options: ParserConfigDict | OpenAPIParserConfigDict | GraphQLParserConfigDict,
additional_options: ParserConfigDict
| JSONSchemaParserConfigDict
| OpenAPIParserConfigDict
| GraphQLParserConfigDict,
) -> _ConfigT:
"""Create a parser config from GenerateConfig with additional options.

Expand Down Expand Up @@ -735,6 +743,28 @@ def get_header_and_first_line(csv_file: IO[str]) -> dict[str, Any]:
),
}

# Convert schema_version string to appropriate enum based on input type
jsonschema_version: JsonSchemaVersion | None = None
openapi_version: OpenAPIVersion | None = None
if config.schema_version and config.schema_version != "auto":
if input_file_type == InputFileType.OpenAPI:
try:
openapi_version = OpenAPIVersion(config.schema_version)
except ValueError:
valid = [v.value for v in OpenAPIVersion]
msg = f"Invalid OpenAPI version: {config.schema_version}. Valid values: {valid}"
raise Error(msg) from None
elif input_file_type == InputFileType.GraphQL:
msg = f"--schema-version is not supported for {input_file_type.value}"
raise Error(msg)
else:
try:
jsonschema_version = JsonSchemaVersion(config.schema_version)
except ValueError:
valid = [v.value for v in JsonSchemaVersion]
msg = f"Invalid JSON Schema version: {config.schema_version}. Valid values: {valid}"
raise Error(msg) from None

if input_file_type == InputFileType.OpenAPI:
from datamodel_code_generator.parser.openapi import OpenAPIParser # noqa: PLC0415

Expand All @@ -743,6 +773,7 @@ def get_header_and_first_line(csv_file: IO[str]) -> dict[str, Any]:
"include_path_parameters": config.include_path_parameters,
"use_status_code_in_response_name": config.use_status_code_in_response_name,
"openapi_include_paths": config.openapi_include_paths,
"openapi_version": openapi_version,
**additional_options,
}
parser_config = _create_parser_config(OpenAPIParserConfig, config, openapi_additional_options)
Expand All @@ -760,7 +791,11 @@ def get_header_and_first_line(csv_file: IO[str]) -> dict[str, Any]:
else:
from datamodel_code_generator.parser.jsonschema import JsonSchemaParser # noqa: PLC0415

parser_config = _create_parser_config(JSONSchemaParserConfig, config, additional_options)
jsonschema_additional_options: JSONSchemaParserConfigDict = {
"jsonschema_version": jsonschema_version,
**additional_options,
}
parser_config = _create_parser_config(JSONSchemaParserConfig, config, jsonschema_additional_options)
parser = JsonSchemaParser(source=source, config=parser_config) # ty: ignore

with chdir(config.output):
Expand Down
5 changes: 5 additions & 0 deletions src/datamodel_code_generator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
ReadOnlyWriteOnlyModelType,
ReuseScope,
TargetPydanticVersion,
VersionMode,
enable_debug_message,
generate,
)
Expand Down Expand Up @@ -620,6 +621,8 @@ def validate_class_name_affix_scope(cls, v: str | ClassNameAffixScope | None) ->
module_split_mode: Optional[ModuleSplitMode] = None # noqa: UP045
watch: bool = False
watch_delay: float = 0.5
schema_version: Optional[str] = None # noqa: UP045
schema_version_mode: Optional[VersionMode] = None # noqa: UP045

def merge_args(self, args: Namespace) -> None:
"""Merge command-line arguments into config."""
Expand Down Expand Up @@ -1063,6 +1066,8 @@ def run_generate_from_config( # noqa: PLR0913, PLR0917
module_split_mode=config.module_split_mode,
validators=validators,
default_value_overrides=default_value_overrides,
schema_version=config.schema_version,
schema_version_mode=config.schema_version_mode,
)

if output is None and result is not None: # pragma: no cover
Expand Down
3 changes: 3 additions & 0 deletions src/datamodel_code_generator/_types/generate_config_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
StrictTypes,
TargetPydanticVersion,
UnionMode,
VersionMode,
)
from datamodel_code_generator.format import DateClassType, DatetimeClassType, Formatter, PythonVersion
from datamodel_code_generator.parser import LiteralType
Expand Down Expand Up @@ -168,6 +169,8 @@ class GenerateConfigDict(TypedDict, closed=True):
field_type_collision_strategy: NotRequired[FieldTypeCollisionStrategy | None]
module_split_mode: NotRequired[ModuleSplitMode | None]
default_value_overrides: NotRequired[Mapping[str, Any] | None]
schema_version: NotRequired[str | None]
schema_version_mode: NotRequired[VersionMode | None]


class ValidatorDefinition(TypedDict):
Expand Down
7 changes: 6 additions & 1 deletion src/datamodel_code_generator/_types/parser_config_dicts.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@
CollapseRootModelsNameStrategy,
DataclassArguments,
FieldTypeCollisionStrategy,
JsonSchemaVersion,
NamingStrategy,
OpenAPIScope,
OpenAPIVersion,
ReadOnlyWriteOnlyModelType,
ReuseScope,
StrictTypes,
TargetPydanticVersion,
VersionMode,
)
from datamodel_code_generator.format import DateClassType, DatetimeClassType, Formatter, PythonVersion
from datamodel_code_generator.model.base import DataModel, DataModelFieldBase
Expand Down Expand Up @@ -167,14 +170,16 @@ class GraphQLParserConfigDict(ParserConfigDict, closed=True):


class JSONSchemaParserConfigDict(ParserConfigDict):
pass
jsonschema_version: NotRequired[JsonSchemaVersion | None]
schema_version_mode: NotRequired[VersionMode | None]


class OpenAPIParserConfigDict(JSONSchemaParserConfigDict, closed=True):
openapi_scopes: NotRequired[list[OpenAPIScope] | None]
include_path_parameters: NotRequired[bool]
use_status_code_in_response_name: NotRequired[bool]
openapi_include_paths: NotRequired[list[str] | None]
openapi_version: NotRequired[OpenAPIVersion | None]


ModelDict: TypeAlias = ParserConfigDict | GraphQLParserConfigDict | JSONSchemaParserConfigDict | OpenAPIParserConfigDict
Expand Down
20 changes: 20 additions & 0 deletions src/datamodel_code_generator/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
StrictTypes,
TargetPydanticVersion,
UnionMode,
VersionMode,
)
from datamodel_code_generator.format import DateClassType, DatetimeClassType, Formatter, PythonVersion
from datamodel_code_generator.parser import LiteralType
Expand Down Expand Up @@ -984,6 +985,25 @@ def start_section(self, heading: str | None) -> None:
action="store_true",
default=None,
)
# ======================================================================================
# Schema version options (for both JSON Schema and OpenAPI)
# ======================================================================================
base_options.add_argument(
"--schema-version",
help="Schema version. Valid values depend on input type: "
"JsonSchema: auto, draft-04, draft-06, draft-07, 2019-09, 2020-12. "
"OpenAPI: auto, 3.0, 3.1. "
"(default: auto - detected from $schema or openapi field)",
default=None,
)
base_options.add_argument(
"--schema-version-mode",
help="Schema version validation mode. "
"'lenient': accept all features regardless of version (default). "
"'strict': warn on features outside declared/detected version.",
choices=[m.value for m in VersionMode],
default=None,
)

# ======================================================================================
# Options specific to GraphQL input schemas
Expand Down
2 changes: 2 additions & 0 deletions src/datamodel_code_generator/cli_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class CLIOptionMeta:
"--input-model-ref-strategy": CLIOptionMeta(name="--input-model-ref-strategy", category=OptionCategory.BASE),
"--input-file-type": CLIOptionMeta(name="--input-file-type", category=OptionCategory.BASE),
"--encoding": CLIOptionMeta(name="--encoding", category=OptionCategory.BASE),
"--schema-version": CLIOptionMeta(name="--schema-version", category=OptionCategory.BASE),
"--schema-version-mode": CLIOptionMeta(name="--schema-version-mode", category=OptionCategory.BASE),
# ==========================================================================
# Model Customization
# ==========================================================================
Expand Down
9 changes: 9 additions & 0 deletions src/datamodel_code_generator/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
FieldTypeCollisionStrategy,
GraphQLScope,
InputFileType,
JsonSchemaVersion,
ModuleSplitMode,
NamingStrategy,
OpenAPIScope,
OpenAPIVersion,
ReadOnlyWriteOnlyModelType,
ReuseScope,
TargetPydanticVersion,
VersionMode,
)
from datamodel_code_generator.format import (
DateClassType,
Expand Down Expand Up @@ -205,6 +208,8 @@ class Config:
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None
module_split_mode: ModuleSplitMode | None = None
default_value_overrides: Mapping[str, Any] | None = None
schema_version: str | None = None
schema_version_mode: VersionMode | None = None


class ParserConfig(BaseModel):
Expand Down Expand Up @@ -350,6 +355,9 @@ class GraphQLParserConfig(ParserConfig):
class JSONSchemaParserConfig(ParserConfig):
"""Configuration model for JsonSchemaParser.__init__()."""

jsonschema_version: JsonSchemaVersion | None = None
schema_version_mode: VersionMode | None = None


class OpenAPIParserConfig(JSONSchemaParserConfig):
"""Configuration model for OpenAPIParser.__init__()."""
Expand All @@ -358,6 +366,7 @@ class OpenAPIParserConfig(JSONSchemaParserConfig):
include_path_parameters: bool = False
use_status_code_in_response_name: bool = False
openapi_include_paths: list[str] | None = None
openapi_version: OpenAPIVersion | None = None


class ParseConfig(BaseModel):
Expand Down
Loading