Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/pip/tomli-2.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
koxudaxi authored Nov 23, 2024
2 parents 0090c33 + 0cba805 commit 21ada6d
Show file tree
Hide file tree
Showing 19 changed files with 265 additions and 174 deletions.
9 changes: 3 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 'v0.7.2'
rev: 'v0.7.4'
hooks:
- id: ruff
files: "^datamodel_code_generator|^tests"
Expand All @@ -18,9 +18,6 @@ repos:
- tomli
exclude: "^tests/|^CODE_OF_CONDUCT.md"
- repo: https://github.com/python-poetry/poetry
rev: 1.8.3
rev: 1.8.0
hooks:
- id: poetry-check
- id: poetry-lock
args:
- --no-update
- id: poetry-check
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ Field customization:
--field-include-all-keys
Add all keys to field parameters
--force-optional Force optional for required fields
--no-alias Do not add a field alias. E.g., if --snake-case-field is used along
with a base class, which has an alias_generator
--original-field-name-delimiter ORIGINAL_FIELD_NAME_DELIMITER
Set delimiter to convert to snake case. This option only can be used
with --snake-case-field (default: `_` )
Expand Down Expand Up @@ -454,8 +456,8 @@ Model customization:
dataclass(kw_only=True)).
--output-datetime-class {datetime,AwareDatetime,NaiveDatetime}
Choose Datetime class between AwareDatetime, NaiveDatetime or
datetime. Each output model has its default mapping, and only
pydantic, dataclass, and msgspec support this override"
datetime. Each output model has its default mapping (for example
pydantic: datetime, dataclass: str, ...)
--reuse-model Reuse models on the field when a module has the model with the same
content
--target-python-version {3.6,3.7,3.8,3.9,3.10,3.11,3.12}
Expand Down
2 changes: 2 additions & 0 deletions datamodel_code_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ def generate(
union_mode: Optional[UnionMode] = None,
output_datetime_class: Optional[DatetimeClassType] = None,
keyword_only: bool = False,
no_alias: bool = False,
) -> None:
remote_text_cache: DefaultPutDict[str, str] = DefaultPutDict()
if isinstance(input_, str):
Expand Down Expand Up @@ -478,6 +479,7 @@ def get_header_and_first_line(csv_file: IO[str]) -> Dict[str, Any]:
default_field_extras=default_field_extras,
target_datetime_class=output_datetime_class,
keyword_only=keyword_only,
no_alias=no_alias,
**kwargs,
)

Expand Down
9 changes: 8 additions & 1 deletion datamodel_code_generator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,13 @@ def validate_custom_file_header(cls, values: Dict[str, Any]) -> Dict[str, Any]:

@model_validator(mode='after')
def validate_keyword_only(cls, values: Dict[str, Any]) -> Dict[str, Any]:
output_model_type: DataModelType = values.get('output_model_type')
python_target: PythonVersion = values.get('target_python_version')
if values.get('keyword_only') and not python_target.has_kw_only_dataclass:
if (
values.get('keyword_only')
and output_model_type == DataModelType.DataclassesDataclass
and not python_target.has_kw_only_dataclass
):
raise Error(
f'`--keyword-only` requires `--target-python-version` {PythonVersion.PY_310.value} or higher.'
)
Expand Down Expand Up @@ -341,6 +346,7 @@ def validate_root(cls, values: Any) -> Any:
union_mode: Optional[UnionMode] = None
output_datetime_class: Optional[DatetimeClassType] = None
keyword_only: bool = False
no_alias: bool = False

def merge_args(self, args: Namespace) -> None:
set_args = {
Expand Down Expand Up @@ -542,6 +548,7 @@ def main(args: Optional[Sequence[str]] = None) -> Exit:
union_mode=config.union_mode,
output_datetime_class=config.output_datetime_class,
keyword_only=config.keyword_only,
no_alias=config.no_alias,
)
return Exit.OK
except InvalidClassNameError as e:
Expand Down
7 changes: 7 additions & 0 deletions datamodel_code_generator/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,13 @@ def start_section(self, heading: Optional[str]) -> None:
choices=[u.value for u in UnionMode],
default=None,
)
field_options.add_argument(
'--no-alias',
help="""Do not add a field alias. E.g., if --snake-case-field is used along with a base class, which has an
alias_generator""",
action='store_true',
default=None,
)

# ======================================================================================
# Options for templating output
Expand Down
5 changes: 3 additions & 2 deletions datamodel_code_generator/model/msgspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
IMPORT_MSGSPEC_CONVERT,
IMPORT_MSGSPEC_FIELD,
IMPORT_MSGSPEC_META,
IMPORT_MSGSPEC_STRUCT,
)
from datamodel_code_generator.model.pydantic.base_model import (
Constraints as _Constraints,
Expand Down Expand Up @@ -88,7 +87,7 @@ class RootModel(_RootModel):
class Struct(DataModel):
TEMPLATE_FILE_PATH: ClassVar[str] = 'msgspec.jinja2'
BASE_CLASS: ClassVar[str] = 'msgspec.Struct'
DEFAULT_IMPORTS: ClassVar[Tuple[Import, ...]] = (IMPORT_MSGSPEC_STRUCT,)
DEFAULT_IMPORTS: ClassVar[Tuple[Import, ...]] = ()

def __init__(
self,
Expand Down Expand Up @@ -123,6 +122,8 @@ def __init__(
keyword_only=keyword_only,
)
self.extra_template_data.setdefault('base_class_kwargs', {})
if self.keyword_only:
self.add_base_class_kwarg('kw_only', 'True')

def add_base_class_kwarg(self, name: str, value):
self.extra_template_data['base_class_kwargs'][name] = value
Expand Down
2 changes: 2 additions & 0 deletions datamodel_code_generator/parser/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ def __init__(
default_field_extras: Optional[Dict[str, Any]] = None,
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
keyword_only: bool = False,
no_alias: bool = False,
) -> None:
self.keyword_only = keyword_only
self.data_type_manager: DataTypeManager = data_type_manager_type(
Expand Down Expand Up @@ -512,6 +513,7 @@ def __init__(
special_field_name_prefix=special_field_name_prefix,
remove_special_field_name_prefix=remove_special_field_name_prefix,
capitalise_enum_members=capitalise_enum_members,
no_alias=no_alias,
)
self.class_name: Optional[str] = class_name
self.wrap_string_literal: Optional[bool] = wrap_string_literal
Expand Down
2 changes: 2 additions & 0 deletions datamodel_code_generator/parser/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def __init__(
default_field_extras: Optional[Dict[str, Any]] = None,
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
keyword_only: bool = False,
no_alias: bool = False,
) -> None:
super().__init__(
source=source,
Expand Down Expand Up @@ -232,6 +233,7 @@ def __init__(
default_field_extras=default_field_extras,
target_datetime_class=target_datetime_class,
keyword_only=keyword_only,
no_alias=no_alias,
)

self.data_model_scalar_type = data_model_scalar_type
Expand Down
5 changes: 5 additions & 0 deletions datamodel_code_generator/parser/jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ def __init__(
default_field_extras: Optional[Dict[str, Any]] = None,
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
keyword_only: bool = False,
no_alias: bool = False,
) -> None:
super().__init__(
source=source,
Expand Down Expand Up @@ -520,6 +521,7 @@ def __init__(
default_field_extras=default_field_extras,
target_datetime_class=target_datetime_class,
keyword_only=keyword_only,
no_alias=no_alias,
)

self.remote_object_cache: DefaultPutDict[str, Dict[str, Any]] = DefaultPutDict()
Expand Down Expand Up @@ -1715,6 +1717,9 @@ def _get_context_source_path_parts(self) -> Iterator[Tuple[Source, List[str]]]:
def parse_raw(self) -> None:
for source, path_parts in self._get_context_source_path_parts():
self.raw_obj = load_yaml(source.text)
if self.raw_obj is None: # pragma: no cover
warn(f'{source.path} is empty. Skipping this file')
continue
if self.custom_class_name_generator:
obj_name = self.raw_obj.get('title', 'Model')
else:
Expand Down
3 changes: 3 additions & 0 deletions datamodel_code_generator/parser/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ def __init__(
default_field_extras: Optional[Dict[str, Any]] = None,
target_datetime_class: DatetimeClassType = DatetimeClassType.Datetime,
keyword_only: bool = False,
no_alias: bool = False,
):
super().__init__(
source=source,
Expand Down Expand Up @@ -300,6 +301,7 @@ def __init__(
default_field_extras=default_field_extras,
target_datetime_class=target_datetime_class,
keyword_only=keyword_only,
no_alias=no_alias,
)
self.open_api_scopes: List[OpenAPIScope] = openapi_scopes or [
OpenAPIScope.Schemas
Expand Down Expand Up @@ -513,6 +515,7 @@ def parse_all_parameters(
fields=fields,
reference=reference,
custom_base_class=self.base_class,
custom_template_dir=self.custom_template_dir,
keyword_only=self.keyword_only,
)
)
Expand Down
15 changes: 12 additions & 3 deletions datamodel_code_generator/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ def __init__(
special_field_name_prefix: Optional[str] = None,
remove_special_field_name_prefix: bool = False,
capitalise_enum_members: bool = False,
no_alias: bool = False,
):
self.aliases: Mapping[str, str] = {} if aliases is None else {**aliases}
self.empty_field_name: str = empty_field_name or '_'
Expand All @@ -208,6 +209,7 @@ def __init__(
)
self.remove_special_field_name_prefix: bool = remove_special_field_name_prefix
self.capitalise_enum_members: bool = capitalise_enum_members
self.no_alias = no_alias

@classmethod
def _validate_field_name(cls, field_name: str) -> bool:
Expand Down Expand Up @@ -274,7 +276,10 @@ def get_valid_field_name_and_alias(
if field_name in self.aliases:
return self.aliases[field_name], field_name
valid_name = self.get_valid_name(field_name, excludes=excludes)
return valid_name, None if field_name == valid_name else field_name
return (
valid_name,
None if self.no_alias or field_name == valid_name else field_name,
)


class PydanticFieldNameResolver(FieldNameResolver):
Expand Down Expand Up @@ -354,6 +359,7 @@ def __init__(
special_field_name_prefix: Optional[str] = None,
remove_special_field_name_prefix: bool = False,
capitalise_enum_members: bool = False,
no_alias: bool = False,
) -> None:
self.references: Dict[str, Reference] = {}
self._current_root: Sequence[str] = []
Expand Down Expand Up @@ -383,6 +389,7 @@ def __init__(
capitalise_enum_members=capitalise_enum_members
if k == ModelType.ENUM
else False,
no_alias=no_alias,
)
for k, v in merged_field_name_resolver_classes.items()
}
Expand Down Expand Up @@ -566,11 +573,13 @@ def add_ref(self, ref: str, resolved: bool = False) -> Reference:
split_ref = ref.rsplit('/', 1)
if len(split_ref) == 1:
original_name = Path(
split_ref[0][:-1] if self.is_external_root_ref(path) else split_ref[0]
split_ref[0].rstrip('#')
if self.is_external_root_ref(path)
else split_ref[0]
).stem
else:
original_name = (
Path(split_ref[1][:-1]).stem
Path(split_ref[1].rstrip('#')).stem
if self.is_external_root_ref(path)
else split_ref[1]
)
Expand Down
6 changes: 4 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ Field customization:
--field-include-all-keys
Add all keys to field parameters
--force-optional Force optional for required fields
--no-alias Do not add a field alias. E.g., if --snake-case-field is used along
with a base class, which has an alias_generator
--original-field-name-delimiter ORIGINAL_FIELD_NAME_DELIMITER
Set delimiter to convert to snake case. This option only can be used
with --snake-case-field (default: `_` )
Expand Down Expand Up @@ -448,8 +450,8 @@ Model customization:
dataclass(kw_only=True)).
--output-datetime-class {datetime,AwareDatetime,NaiveDatetime}
Choose Datetime class between AwareDatetime, NaiveDatetime or
datetime. Each output model has its default mapping, and only
pydantic, dataclass, and msgspec support this override"
datetime. Each output model has its default mapping (for example
pydantic: datetime, dataclass: str, ...)
--reuse-model Reuse models on the field when a module has the model with the same
content
--target-python-version {3.6,3.7,3.8,3.9,3.10,3.11,3.12}
Expand Down
Loading

0 comments on commit 21ada6d

Please sign in to comment.