Skip to content

Commit 0c5d538

Browse files
authored
Simplify Parser.__init__ signature using Unpack[ParserConfigDict] (#2877)
* Add type and default value checks to test_parser_signature_matches_baseline * Simplify Parser.__init__ signature using Unpack[ParserConfigDict] * Fix kwargs to options and add tests for config+options ValueError * Add tests for explicit parser options to cover else branches * Remove unreachable code in parser signature test * Add tests for parsers with config object to cover config is not None branch
1 parent 0610118 commit 0c5d538

6 files changed

Lines changed: 372 additions & 864 deletions

File tree

src/datamodel_code_generator/parser/base.py

Lines changed: 162 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
from warnings import warn
2222

2323
from pydantic import BaseModel
24+
from typing_extensions import Unpack
2425

2526
from datamodel_code_generator import (
26-
DEFAULT_SHARED_MODULE_NAME,
2727
AllExportsCollisionStrategy,
2828
AllExportsScope,
2929
AllOfClassHierarchy,
@@ -32,20 +32,14 @@
3232
Error,
3333
FieldTypeCollisionStrategy,
3434
ModuleSplitMode,
35-
NamingStrategy,
3635
ReadOnlyWriteOnlyModelType,
3736
ReuseScope,
38-
TargetPydanticVersion,
3937
YamlValue,
4038
)
4139
from datamodel_code_generator.format import (
42-
DEFAULT_FORMATTERS,
4340
CodeFormatter,
44-
DateClassType,
45-
DatetimeClassType,
4641
Formatter,
4742
PythonVersion,
48-
PythonVersionMin,
4943
)
5044
from datamodel_code_generator.imports import (
5145
IMPORT_ANNOTATIONS,
@@ -76,13 +70,14 @@
7670
from datamodel_code_generator.parser._graph import stable_toposort
7771
from datamodel_code_generator.parser._scc import find_circular_sccs, strongly_connected_components
7872
from datamodel_code_generator.reference import ModelResolver, ModelType, Reference
79-
from datamodel_code_generator.types import DataType, DataTypeManager, StrictTypes
80-
from datamodel_code_generator.util import camel_to_snake, model_copy, model_dump
73+
from datamodel_code_generator.types import DataType, DataTypeManager
74+
from datamodel_code_generator.util import camel_to_snake, is_pydantic_v2, model_copy, model_dump
8175

8276
if TYPE_CHECKING:
83-
from collections.abc import Iterable, Iterator, Mapping, Sequence
77+
from collections.abc import Iterable, Iterator, Sequence
8478

85-
from datamodel_code_generator import DataclassArguments
79+
from datamodel_code_generator._types import ParserConfigDict
80+
from datamodel_code_generator.config import ParserConfig
8681

8782

8883
@runtime_checkable
@@ -687,123 +682,166 @@ class Parser(ABC):
687682
parse_raw() to handle specific schema formats.
688683
"""
689684

690-
def __init__( # noqa: PLR0912, PLR0913, PLR0915
685+
def __init__( # noqa: PLR0912, PLR0914, PLR0915
691686
self,
692687
source: str | Path | list[Path] | ParseResult | dict[str, YamlValue],
693688
*,
694-
data_model_type: type[DataModel] = pydantic_model.BaseModel,
695-
data_model_root_type: type[DataModel] = pydantic_model.CustomRootType,
696-
data_type_manager_type: type[DataTypeManager] = pydantic_model.DataTypeManager,
697-
data_model_field_type: type[DataModelFieldBase] = pydantic_model.DataModelField,
698-
base_class: str | None = None,
699-
base_class_map: dict[str, str] | None = None,
700-
additional_imports: list[str] | None = None,
701-
class_decorators: list[str] | None = None,
702-
custom_template_dir: Path | None = None,
703-
extra_template_data: defaultdict[str, dict[str, Any]] | None = None,
704-
target_python_version: PythonVersion = PythonVersionMin,
705-
dump_resolve_reference_action: Callable[[Iterable[str]], str] | None = None,
706-
validation: bool = False,
707-
field_constraints: bool = False,
708-
snake_case_field: bool = False,
709-
strip_default_none: bool = False,
710-
aliases: Mapping[str, str | list[str]] | None = None,
711-
allow_population_by_field_name: bool = False,
712-
apply_default_values_for_required_fields: bool = False,
713-
allow_extra_fields: bool = False,
714-
extra_fields: str | None = None,
715-
use_generic_base_class: bool = False,
716-
force_optional_for_required_fields: bool = False,
717-
class_name: str | None = None,
718-
use_standard_collections: bool = False,
719-
base_path: Path | None = None,
720-
use_schema_description: bool = False,
721-
use_field_description: bool = False,
722-
use_field_description_example: bool = False,
723-
use_attribute_docstrings: bool = False,
724-
use_inline_field_description: bool = False,
725-
use_default_kwarg: bool = False,
726-
reuse_model: bool = False,
727-
reuse_scope: ReuseScope | None = None,
728-
shared_module_name: str = DEFAULT_SHARED_MODULE_NAME,
729-
encoding: str = "utf-8",
730-
enum_field_as_literal: LiteralType | None = None,
731-
enum_field_as_literal_map: dict[str, str] | None = None,
732-
ignore_enum_constraints: bool = False,
733-
set_default_enum_member: bool = False,
734-
use_subclass_enum: bool = False,
735-
use_specialized_enum: bool = True,
736-
strict_nullable: bool = False,
737-
use_generic_container_types: bool = False,
738-
enable_faux_immutability: bool = False,
739-
remote_text_cache: DefaultPutDict[str, str] | None = None,
740-
disable_appending_item_suffix: bool = False,
741-
strict_types: Sequence[StrictTypes] | None = None,
742-
empty_enum_field_name: str | None = None,
743-
custom_class_name_generator: Callable[[str], str] | None = title_to_class_name,
744-
field_extra_keys: set[str] | None = None,
745-
field_include_all_keys: bool = False,
746-
field_extra_keys_without_x_prefix: set[str] | None = None,
747-
model_extra_keys: set[str] | None = None,
748-
model_extra_keys_without_x_prefix: set[str] | None = None,
749-
wrap_string_literal: bool | None = None,
750-
use_title_as_name: bool = False,
751-
use_operation_id_as_name: bool = False,
752-
use_unique_items_as_set: bool = False,
753-
use_tuple_for_fixed_items: bool = False,
754-
allof_merge_mode: AllOfMergeMode = AllOfMergeMode.Constraints,
755-
allof_class_hierarchy: AllOfClassHierarchy = AllOfClassHierarchy.IfNoConflict,
756-
http_headers: Sequence[tuple[str, str]] | None = None,
757-
http_ignore_tls: bool = False,
758-
http_timeout: float | None = None,
759-
use_annotated: bool = False,
760-
use_serialize_as_any: bool = False,
761-
use_non_positive_negative_number_constrained_types: bool = False,
762-
use_decimal_for_multiple_of: bool = False,
763-
original_field_name_delimiter: str | None = None,
764-
use_double_quotes: bool = False,
765-
use_union_operator: bool = False,
766-
allow_responses_without_content: bool = False,
767-
collapse_root_models: bool = False,
768-
collapse_root_models_name_strategy: CollapseRootModelsNameStrategy | None = None,
769-
collapse_reuse_models: bool = False,
770-
skip_root_model: bool = False,
771-
use_type_alias: bool = False,
772-
special_field_name_prefix: str | None = None,
773-
remove_special_field_name_prefix: bool = False,
774-
capitalise_enum_members: bool = False,
775-
keep_model_order: bool = False,
776-
use_one_literal_as_default: bool = False,
777-
use_enum_values_in_discriminator: bool = False,
778-
known_third_party: list[str] | None = None,
779-
custom_formatters: list[str] | None = None,
780-
custom_formatters_kwargs: dict[str, Any] | None = None,
781-
use_pendulum: bool = False,
782-
use_standard_primitive_types: bool = False,
783-
http_query_parameters: Sequence[tuple[str, str]] | None = None,
784-
treat_dot_as_module: bool | None = None,
785-
use_exact_imports: bool = False,
786-
default_field_extras: dict[str, Any] | None = None,
787-
target_datetime_class: DatetimeClassType | None = None,
788-
target_date_class: DateClassType | None = None,
789-
keyword_only: bool = False,
790-
frozen_dataclasses: bool = False,
791-
no_alias: bool = False,
792-
use_frozen_field: bool = False,
793-
use_default_factory_for_optional_nested_models: bool = False,
794-
formatters: list[Formatter] = DEFAULT_FORMATTERS,
795-
defer_formatting: bool = False,
796-
parent_scoped_naming: bool = False,
797-
naming_strategy: NamingStrategy | None = None,
798-
duplicate_name_suffix: dict[str, str] | None = None,
799-
dataclass_arguments: DataclassArguments | None = None,
800-
type_mappings: list[str] | None = None,
801-
type_overrides: dict[str, str] | None = None,
802-
read_only_write_only_model_type: ReadOnlyWriteOnlyModelType | None = None,
803-
field_type_collision_strategy: FieldTypeCollisionStrategy | None = None,
804-
target_pydantic_version: TargetPydanticVersion | None = None,
689+
config: ParserConfig | None = None,
690+
**options: Unpack[ParserConfigDict],
805691
) -> None:
806-
"""Initialize the Parser with configuration options."""
692+
"""Initialize the Parser with configuration options.
693+
694+
Args:
695+
source: The schema source to parse.
696+
config: Optional ParserConfig object with all configuration options.
697+
**options: Individual configuration options (alternative to config).
698+
699+
Raises:
700+
ValueError: If both config and **options are provided.
701+
"""
702+
from datamodel_code_generator.config import ParserConfig # noqa: PLC0415
703+
704+
if config is not None and options:
705+
msg = "Cannot specify both 'config' and keyword arguments. Use one or the other."
706+
raise ValueError(msg)
707+
708+
if config is None:
709+
from datamodel_code_generator import types as types_module # noqa: PLC0415
710+
from datamodel_code_generator.model import base as model_base # noqa: PLC0415
711+
712+
if is_pydantic_v2():
713+
ParserConfig.model_rebuild(
714+
_types_namespace={
715+
"StrictTypes": types_module.StrictTypes,
716+
"DataModel": model_base.DataModel,
717+
"DataModelFieldBase": model_base.DataModelFieldBase,
718+
"DataTypeManager": types_module.DataTypeManager,
719+
}
720+
)
721+
config = ParserConfig.model_validate(options)
722+
else:
723+
ParserConfig.update_forward_refs(
724+
StrictTypes=types_module.StrictTypes,
725+
DataModel=model_base.DataModel,
726+
DataModelFieldBase=model_base.DataModelFieldBase,
727+
DataTypeManager=types_module.DataTypeManager,
728+
)
729+
defaults = {name: field.default for name, field in ParserConfig.__fields__.items()}
730+
defaults.update(options)
731+
config = ParserConfig.construct(**defaults)
732+
733+
data_model_type = config.data_model_type
734+
data_model_root_type = config.data_model_root_type
735+
data_type_manager_type = config.data_type_manager_type
736+
data_model_field_type = config.data_model_field_type
737+
base_class = config.base_class
738+
base_class_map = config.base_class_map
739+
additional_imports = config.additional_imports
740+
class_decorators = config.class_decorators
741+
custom_template_dir = config.custom_template_dir
742+
extra_template_data = config.extra_template_data
743+
target_python_version = config.target_python_version
744+
dump_resolve_reference_action = config.dump_resolve_reference_action
745+
validation = config.validation
746+
field_constraints = config.field_constraints
747+
snake_case_field = config.snake_case_field
748+
strip_default_none = config.strip_default_none
749+
aliases = config.aliases
750+
allow_population_by_field_name = config.allow_population_by_field_name
751+
apply_default_values_for_required_fields = config.apply_default_values_for_required_fields
752+
allow_extra_fields = config.allow_extra_fields
753+
extra_fields = config.extra_fields
754+
use_generic_base_class = config.use_generic_base_class
755+
force_optional_for_required_fields = config.force_optional_for_required_fields
756+
class_name = config.class_name
757+
use_standard_collections = config.use_standard_collections
758+
base_path = config.base_path
759+
use_schema_description = config.use_schema_description
760+
use_field_description = config.use_field_description
761+
use_field_description_example = config.use_field_description_example
762+
use_attribute_docstrings = config.use_attribute_docstrings
763+
use_inline_field_description = config.use_inline_field_description
764+
use_default_kwarg = config.use_default_kwarg
765+
reuse_model = config.reuse_model
766+
reuse_scope = config.reuse_scope
767+
shared_module_name = config.shared_module_name
768+
encoding = config.encoding
769+
enum_field_as_literal = config.enum_field_as_literal
770+
enum_field_as_literal_map = config.enum_field_as_literal_map
771+
ignore_enum_constraints = config.ignore_enum_constraints
772+
set_default_enum_member = config.set_default_enum_member
773+
use_subclass_enum = config.use_subclass_enum
774+
use_specialized_enum = config.use_specialized_enum
775+
strict_nullable = config.strict_nullable
776+
use_generic_container_types = config.use_generic_container_types
777+
enable_faux_immutability = config.enable_faux_immutability
778+
remote_text_cache = config.remote_text_cache
779+
disable_appending_item_suffix = config.disable_appending_item_suffix
780+
strict_types = config.strict_types
781+
empty_enum_field_name = config.empty_enum_field_name
782+
custom_class_name_generator = config.custom_class_name_generator
783+
field_extra_keys = config.field_extra_keys
784+
field_include_all_keys = config.field_include_all_keys
785+
field_extra_keys_without_x_prefix = config.field_extra_keys_without_x_prefix
786+
model_extra_keys = config.model_extra_keys
787+
model_extra_keys_without_x_prefix = config.model_extra_keys_without_x_prefix
788+
wrap_string_literal = config.wrap_string_literal
789+
use_title_as_name = config.use_title_as_name
790+
use_operation_id_as_name = config.use_operation_id_as_name
791+
use_unique_items_as_set = config.use_unique_items_as_set
792+
use_tuple_for_fixed_items = config.use_tuple_for_fixed_items
793+
allof_merge_mode = config.allof_merge_mode
794+
allof_class_hierarchy = config.allof_class_hierarchy
795+
http_headers = config.http_headers
796+
http_ignore_tls = config.http_ignore_tls
797+
http_timeout = config.http_timeout
798+
use_annotated = config.use_annotated
799+
use_serialize_as_any = config.use_serialize_as_any
800+
use_non_positive_negative_number_constrained_types = config.use_non_positive_negative_number_constrained_types
801+
use_decimal_for_multiple_of = config.use_decimal_for_multiple_of
802+
original_field_name_delimiter = config.original_field_name_delimiter
803+
use_double_quotes = config.use_double_quotes
804+
use_union_operator = config.use_union_operator
805+
allow_responses_without_content = config.allow_responses_without_content
806+
collapse_root_models = config.collapse_root_models
807+
collapse_root_models_name_strategy = config.collapse_root_models_name_strategy
808+
collapse_reuse_models = config.collapse_reuse_models
809+
skip_root_model = config.skip_root_model
810+
use_type_alias = config.use_type_alias
811+
special_field_name_prefix = config.special_field_name_prefix
812+
remove_special_field_name_prefix = config.remove_special_field_name_prefix
813+
capitalise_enum_members = config.capitalise_enum_members
814+
keep_model_order = config.keep_model_order
815+
use_one_literal_as_default = config.use_one_literal_as_default
816+
use_enum_values_in_discriminator = config.use_enum_values_in_discriminator
817+
known_third_party = config.known_third_party
818+
custom_formatters = config.custom_formatters
819+
custom_formatters_kwargs = config.custom_formatters_kwargs
820+
use_pendulum = config.use_pendulum
821+
use_standard_primitive_types = config.use_standard_primitive_types
822+
http_query_parameters = config.http_query_parameters
823+
treat_dot_as_module = config.treat_dot_as_module
824+
use_exact_imports = config.use_exact_imports
825+
default_field_extras = config.default_field_extras
826+
target_datetime_class = config.target_datetime_class
827+
target_date_class = config.target_date_class
828+
keyword_only = config.keyword_only
829+
frozen_dataclasses = config.frozen_dataclasses
830+
no_alias = config.no_alias
831+
use_frozen_field = config.use_frozen_field
832+
use_default_factory_for_optional_nested_models = config.use_default_factory_for_optional_nested_models
833+
formatters = config.formatters
834+
defer_formatting = config.defer_formatting
835+
parent_scoped_naming = config.parent_scoped_naming
836+
naming_strategy = config.naming_strategy
837+
duplicate_name_suffix = config.duplicate_name_suffix
838+
dataclass_arguments = config.dataclass_arguments
839+
type_mappings = config.type_mappings
840+
type_overrides = config.type_overrides
841+
read_only_write_only_model_type = config.read_only_write_only_model_type
842+
field_type_collision_strategy = config.field_type_collision_strategy
843+
target_pydantic_version = config.target_pydantic_version
844+
807845
self.keyword_only = keyword_only
808846
self.target_pydantic_version = target_pydantic_version
809847
self.frozen_dataclasses = frozen_dataclasses

0 commit comments

Comments
 (0)