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
3 changes: 2 additions & 1 deletion docs/cli-reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This documentation is auto-generated from test cases.
| Category | Options | Description |
|----------|---------|-------------|
| 📁 [Base Options](base-options.md) | 5 | Input/output configuration |
| 🔧 [Typing Customization](typing-customization.md) | 18 | Type annotation and import behavior |
| 🔧 [Typing Customization](typing-customization.md) | 19 | Type annotation and import behavior |
| 🏷️ [Field Customization](field-customization.md) | 21 | Field naming and docstring behavior |
| 🏗️ [Model Customization](model-customization.md) | 29 | Model generation behavior |
| 🎨 [Template Customization](template-customization.md) | 16 | Output formatting and custom rendering |
Expand Down Expand Up @@ -123,6 +123,7 @@ This documentation is auto-generated from test cases.
- [`--openapi-scopes`](openapi-only-options.md#openapi-scopes)
- [`--original-field-name-delimiter`](field-customization.md#original-field-name-delimiter)
- [`--output`](base-options.md#output)
- [`--output-date-class`](typing-customization.md#output-date-class)
- [`--output-datetime-class`](typing-customization.md#output-datetime-class)
- [`--output-model-type`](model-customization.md#output-model-type)

Expand Down
2 changes: 2 additions & 0 deletions docs/cli-reference/quick-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ datamodel-codegen [OPTIONS]
| [`--no-use-specialized-enum`](typing-customization.md#no-use-specialized-enum) | Disable specialized Enum classes for Python 3.11+ code generation. |
| [`--no-use-standard-collections`](typing-customization.md#no-use-standard-collections) | Use built-in dict/list instead of typing.Dict/List. |
| [`--no-use-union-operator`](typing-customization.md#no-use-union-operator) | Test GraphQL annotated types with standard collections and union operator. |
| [`--output-date-class`](typing-customization.md#output-date-class) | Specify date class type for date schema fields. |
| [`--output-datetime-class`](typing-customization.md#output-datetime-class) | Specify datetime class type for date-time schema fields. |
| [`--strict-types`](typing-customization.md#strict-types) | Enable strict type validation for specified Python types. |
| [`--type-mappings`](typing-customization.md#type-mappings) | Override default type mappings for schema formats. |
Expand Down Expand Up @@ -235,6 +236,7 @@ All options sorted alphabetically:
- [`--openapi-scopes`](openapi-only-options.md#openapi-scopes) - Specify OpenAPI scopes to generate (schemas, paths, paramete...
- [`--original-field-name-delimiter`](field-customization.md#original-field-name-delimiter) - Specify delimiter for original field names when using snake-...
- [`--output`](base-options.md#output) - Specify the destination path for generated Python code.
- [`--output-date-class`](typing-customization.md#output-date-class) - Specify date class type for date schema fields.
- [`--output-datetime-class`](typing-customization.md#output-datetime-class) - Specify datetime class type for date-time schema fields.
- [`--output-model-type`](model-customization.md#output-model-type) - Select the output model type (Pydantic v1/v2, dataclasses, T...
- [`--parent-scoped-naming`](model-customization.md#parent-scoped-naming) - Namespace models by their parent scope to avoid naming confl...
Expand Down
54 changes: 54 additions & 0 deletions docs/cli-reference/typing-customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
| [`--no-use-specialized-enum`](#no-use-specialized-enum) | Disable specialized Enum classes for Python 3.11+ code gener... |
| [`--no-use-standard-collections`](#no-use-standard-collections) | Use built-in dict/list instead of typing.Dict/List. |
| [`--no-use-union-operator`](#no-use-union-operator) | Test GraphQL annotated types with standard collections and u... |
| [`--output-date-class`](#output-date-class) | Specify date class type for date schema fields. |
| [`--output-datetime-class`](#output-datetime-class) | Specify datetime class type for date-time schema fields. |
| [`--strict-types`](#strict-types) | Enable strict type validation for specified Python types. |
| [`--type-mappings`](#type-mappings) | Override default type mappings for schema formats. |
Expand Down Expand Up @@ -1870,6 +1871,59 @@ Test GraphQL annotated types with standard collections and union operator.

---

## `--output-date-class` {#output-date-class}

Specify date class type for date schema fields.

The `--output-date-class` flag controls which date type to use for fields
with date format. Options include 'PastDate' for past dates only
or 'FutureDate' for future dates only. This is a Pydantic v2 only feature.

!!! tip "Usage"

```bash
datamodel-codegen --input schema.json --output-date-class PastDate # (1)!
```

1. :material-arrow-left: `--output-date-class` - the option documented here

??? example "Examples"

**Input Schema:**

```yaml
openapi: "3.0.0"
components:
schemas:
Event:
type: object
required:
- eventDate
properties:
eventDate:
type: string
format: date
example: 2023-12-25
```

**Output:**

```python
# generated by datamodel-codegen:
# filename: date_class.yaml
# timestamp: 1985-10-26T08:21:00+00:00

from __future__ import annotations

from pydantic import BaseModel, Field, PastDate


class Event(BaseModel):
eventDate: PastDate = Field(..., examples=['2023-12-25'])
```

---

## `--output-datetime-class` {#output-datetime-class}

Specify datetime class type for date-time schema fields.
Expand Down
4 changes: 4 additions & 0 deletions src/datamodel_code_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import datamodel_code_generator.pydantic_patch # noqa: F401
from datamodel_code_generator.format import (
DEFAULT_FORMATTERS,
DateClassType,
DatetimeClassType,
Formatter,
PythonVersion,
Expand Down Expand Up @@ -481,6 +482,7 @@ def generate( # noqa: PLR0912, PLR0913, PLR0914, PLR0915
use_exact_imports: bool = False,
union_mode: UnionMode | None = None,
output_datetime_class: DatetimeClassType | None = None,
output_date_class: DateClassType | None = None,
keyword_only: bool = False,
frozen_dataclasses: bool = False,
no_alias: bool = False,
Expand Down Expand Up @@ -733,6 +735,7 @@ def get_header_and_first_line(csv_file: IO[str]) -> dict[str, Any]:
use_exact_imports=use_exact_imports,
default_field_extras=default_field_extras,
target_datetime_class=output_datetime_class,
target_date_class=output_date_class,
keyword_only=keyword_only,
frozen_dataclasses=frozen_dataclasses,
no_alias=no_alias,
Expand Down Expand Up @@ -888,6 +891,7 @@ def infer_input_type(text: str) -> InputFileType:
"MIN_VERSION",
"AllExportsCollisionStrategy",
"AllExportsScope",
"DateClassType",
"DatetimeClassType",
"DefaultPutDict",
"Error",
Expand Down
3 changes: 3 additions & 0 deletions src/datamodel_code_generator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from datamodel_code_generator.arguments import DEFAULT_ENCODING, arg_parser, namespace
from datamodel_code_generator.format import (
DEFAULT_FORMATTERS,
DateClassType,
DatetimeClassType,
Formatter,
PythonVersion,
Expand Down Expand Up @@ -458,6 +459,7 @@ def validate_all_exports_collision_strategy(cls, values: dict[str, Any]) -> dict
use_exact_imports: bool = False
union_mode: Optional[UnionMode] = None # noqa: UP045
output_datetime_class: Optional[DatetimeClassType] = None # noqa: UP045
output_date_class: Optional[DateClassType] = None # noqa: UP045
keyword_only: bool = False
frozen_dataclasses: bool = False
dataclass_arguments: Optional[DataclassArguments] = None # noqa: UP045
Expand Down Expand Up @@ -766,6 +768,7 @@ def run_generate_from_config( # noqa: PLR0913, PLR0917
use_exact_imports=config.use_exact_imports,
union_mode=config.union_mode,
output_datetime_class=config.output_datetime_class,
output_date_class=config.output_date_class,
keyword_only=config.keyword_only,
frozen_dataclasses=config.frozen_dataclasses,
no_alias=config.no_alias,
Expand Down
11 changes: 9 additions & 2 deletions src/datamodel_code_generator/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
ReadOnlyWriteOnlyModelType,
ReuseScope,
)
from datamodel_code_generator.format import DatetimeClassType, Formatter, PythonVersion
from datamodel_code_generator.format import DateClassType, DatetimeClassType, Formatter, PythonVersion
from datamodel_code_generator.model.pydantic_v2 import UnionMode
from datamodel_code_generator.parser import LiteralType
from datamodel_code_generator.types import StrictTypes
Expand Down Expand Up @@ -320,11 +320,18 @@ def start_section(self, heading: str | None) -> None:
)
model_options.add_argument(
"--output-datetime-class",
help="Choose Datetime class between AwareDatetime, NaiveDatetime or datetime. "
help="Choose Datetime class between AwareDatetime, NaiveDatetime, PastDatetime, FutureDatetime or datetime. "
"Each output model has its default mapping (for example pydantic: datetime, dataclass: str, ...)",
choices=[i.value for i in DatetimeClassType],
default=None,
)
model_options.add_argument(
"--output-date-class",
help="Choose Date class between PastDate, FutureDate or date. (Pydantic v2 only) "
"Each output model has its default mapping.",
choices=[i.value for i in DateClassType],
default=None,
)
model_options.add_argument(
"--parent-scoped-naming",
help="Set name of models defined inline from the parent model",
Expand Down
1 change: 1 addition & 0 deletions src/datamodel_code_generator/cli_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ class CLIOptionMeta:
name="--use-standard-primitive-types", category=OptionCategory.TYPING
),
"--output-datetime-class": CLIOptionMeta(name="--output-datetime-class", category=OptionCategory.TYPING),
"--output-date-class": CLIOptionMeta(name="--output-date-class", category=OptionCategory.TYPING),
"--use-decimal-for-multiple-of": CLIOptionMeta(
name="--use-decimal-for-multiple-of", category=OptionCategory.TYPING
),
Expand Down
10 changes: 10 additions & 0 deletions src/datamodel_code_generator/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ class DatetimeClassType(Enum):
Datetime = "datetime"
Awaredatetime = "AwareDatetime"
Naivedatetime = "NaiveDatetime"
Pastdatetime = "PastDatetime"
Futuredatetime = "FutureDatetime"


class DateClassType(Enum):
"""Output date class type options."""

Date = "date"
Pastdate = "PastDate"
Futuredate = "FutureDate"


class PythonVersion(Enum):
Expand Down
33 changes: 20 additions & 13 deletions src/datamodel_code_generator/model/dataclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@

from typing import TYPE_CHECKING, Any, ClassVar, Optional

from datamodel_code_generator import DataclassArguments, DatetimeClassType, PythonVersion, PythonVersionMin
from datamodel_code_generator import (
DataclassArguments,
DateClassType,
DatetimeClassType,
PythonVersion,
PythonVersionMin,
)
from datamodel_code_generator.imports import (
IMPORT_DATE,
IMPORT_DATETIME,
Expand Down Expand Up @@ -219,23 +225,24 @@ def __init__( # noqa: PLR0913, PLR0917
use_pendulum: bool = False, # noqa: FBT001, FBT002
use_standard_primitive_types: bool = False, # noqa: FBT001, FBT002
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
target_date_class: DateClassType | None = None, # noqa: ARG002
treat_dot_as_module: bool | None = None, # noqa: FBT001
use_serialize_as_any: bool = False, # noqa: FBT001, FBT002
) -> None:
"""Initialize type manager with datetime type mapping."""
super().__init__(
python_version,
use_standard_collections,
use_generic_container_types,
strict_types,
use_non_positive_negative_number_constrained_types,
use_decimal_for_multiple_of,
use_union_operator,
use_pendulum,
use_standard_primitive_types,
target_datetime_class,
treat_dot_as_module,
use_serialize_as_any,
python_version=python_version,
use_standard_collections=use_standard_collections,
use_generic_container_types=use_generic_container_types,
strict_types=strict_types,
use_non_positive_negative_number_constrained_types=use_non_positive_negative_number_constrained_types,
use_decimal_for_multiple_of=use_decimal_for_multiple_of,
use_union_operator=use_union_operator,
use_pendulum=use_pendulum,
use_standard_primitive_types=use_standard_primitive_types,
target_datetime_class=target_datetime_class,
treat_dot_as_module=treat_dot_as_module,
use_serialize_as_any=use_serialize_as_any,
)

datetime_map = (
Expand Down
27 changes: 14 additions & 13 deletions src/datamodel_code_generator/model/msgspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from pydantic import Field

from datamodel_code_generator import DatetimeClassType, PythonVersion, PythonVersionMin
from datamodel_code_generator import DateClassType, DatetimeClassType, PythonVersion, PythonVersionMin
from datamodel_code_generator.imports import (
IMPORT_DATE,
IMPORT_DATETIME,
Expand Down Expand Up @@ -505,23 +505,24 @@ def __init__( # noqa: PLR0913, PLR0917
use_pendulum: bool = False, # noqa: FBT001, FBT002
use_standard_primitive_types: bool = False, # noqa: FBT001, FBT002
target_datetime_class: DatetimeClassType | None = None,
target_date_class: DateClassType | None = None, # noqa: ARG002
treat_dot_as_module: bool | None = None, # noqa: FBT001
use_serialize_as_any: bool = False, # noqa: FBT001, FBT002
) -> None:
"""Initialize type manager with optional datetime type mapping."""
super().__init__(
python_version,
use_standard_collections,
use_generic_container_types,
strict_types,
use_non_positive_negative_number_constrained_types,
use_decimal_for_multiple_of,
use_union_operator,
use_pendulum,
use_standard_primitive_types,
target_datetime_class,
treat_dot_as_module,
use_serialize_as_any,
python_version=python_version,
use_standard_collections=use_standard_collections,
use_generic_container_types=use_generic_container_types,
strict_types=strict_types,
use_non_positive_negative_number_constrained_types=use_non_positive_negative_number_constrained_types,
use_decimal_for_multiple_of=use_decimal_for_multiple_of,
use_union_operator=use_union_operator,
use_pendulum=use_pendulum,
use_standard_primitive_types=use_standard_primitive_types,
target_datetime_class=target_datetime_class,
treat_dot_as_module=treat_dot_as_module,
use_serialize_as_any=use_serialize_as_any,
)

datetime_map = (
Expand Down
5 changes: 4 additions & 1 deletion src/datamodel_code_generator/model/pydantic/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from decimal import Decimal
from typing import TYPE_CHECKING, Any, ClassVar

from datamodel_code_generator.format import DatetimeClassType, PythonVersion, PythonVersionMin
from datamodel_code_generator.format import DateClassType, DatetimeClassType, PythonVersion, PythonVersionMin
from datamodel_code_generator.imports import (
IMPORT_ANY,
IMPORT_DATE,
Expand Down Expand Up @@ -86,6 +86,8 @@ def type_map_factory(
Types.binary: data_type(type="bytes"),
Types.date: data_type.from_import(IMPORT_DATE),
Types.date_time: data_type.from_import(IMPORT_DATETIME),
Types.date_time_local: data_type.from_import(IMPORT_DATETIME),
Types.time_local: data_type.from_import(IMPORT_TIME),
Types.timedelta: data_type.from_import(IMPORT_TIMEDELTA),
Types.path: data_type.from_import(IMPORT_PATH),
Types.password: data_type.from_import(IMPORT_SECRET_STR),
Expand Down Expand Up @@ -182,6 +184,7 @@ def __init__( # noqa: PLR0913, PLR0917
use_pendulum: bool = False, # noqa: FBT001, FBT002
use_standard_primitive_types: bool = False, # noqa: FBT001, FBT002, ARG002
target_datetime_class: DatetimeClassType | None = None,
target_date_class: DateClassType | None = None, # noqa: ARG002
treat_dot_as_module: bool | None = None, # noqa: FBT001
use_serialize_as_any: bool = False, # noqa: FBT001, FBT002
) -> None:
Expand Down
5 changes: 4 additions & 1 deletion src/datamodel_code_generator/model/pydantic_v2/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
IMPORT_CONFIG_DICT = Import.from_full_path("pydantic.ConfigDict")
IMPORT_AWARE_DATETIME = Import.from_full_path("pydantic.AwareDatetime")
IMPORT_NAIVE_DATETIME = Import.from_full_path("pydantic.NaiveDatetime")
IMPORT_PAST_DATETIME = Import.from_full_path("pydantic.PastDatetime")
IMPORT_FUTURE_DATETIME = Import.from_full_path("pydantic.FutureDatetime")
IMPORT_PAST_DATE = Import.from_full_path("pydantic.PastDate")
IMPORT_FUTURE_DATE = Import.from_full_path("pydantic.FutureDate")
IMPORT_BASE64STR = Import.from_full_path("pydantic.Base64Str")
# IMPORT_BASE64STR: Used for OpenAPI strings with format "byte" (base64 encoded characters).
IMPORT_SERIALIZE_AS_ANY = Import.from_full_path("pydantic.SerializeAsAny")
Loading
Loading