Dataclass transform change init False

This commit is contained in:
Eric Masseran
2025-03-18 00:30:50 +01:00
parent e140523211
commit 999332ef77
3 changed files with 61 additions and 3 deletions

View File

@@ -296,7 +296,9 @@ class ClassMixin:
continue
# All inherited behave like dataclass
if is_dataclass_transform_with_init:
if is_dataclass_transform_with_init and (
isinstance(cls, ClassValue) and not cls._has_init_false()
):
param_names.extend(
get_dataclass_param_names(cls)
)
@@ -557,6 +559,27 @@ class ClassValue(ClassMixin, FunctionAndClassBase, metaclass=CachedMetaClass):
return values
return NO_VALUES
def _has_init_false(self) -> bool:
"""
It returns ``True`` if ``class X(init=False):`` else ``False``.
"""
bases_arguments = self._get_bases_arguments()
if bases_arguments.argument_node.type != "arglist":
# If it is not inheriting from the base model and having
# extra parameters, then init behavior is not changed.
return False
for arg in bases_arguments.argument_node.children:
if (
arg.type == "argument"
and arg.children[0].value == "init"
and arg.children[2].value == "False"
):
return True
return False
@plugin_manager.decorate()
def get_metaclass_signatures(self, metaclasses):
return []

View File

@@ -625,9 +625,17 @@ def _dataclass(value, arguments, callback):
]
)
elif c.is_function():
# dataclass_transform on a decorator equivalent of @dataclass
# @dataclass_transform
# def create_model(): pass
return ValueSet([value])
elif value.name.string_name != "dataclass_transform":
elif (
# @dataclass(...)
value.name.string_name != "dataclass_transform"
# @dataclass_transform
# def create_model(): pass
# @create_model(...)
or isinstance(value, Decoratee)
):
# dataclass (or like) decorator customization
return ValueSet(
[

View File

@@ -482,6 +482,30 @@ dataclass_transform_cases = [
def __init__(self, toto: str):
pass
'''), ["toto"], False],
# Class based init=false
[dedent('''
@dataclass_transform
class Y():
y: int
z = 5
class X(Y, init=False):'''), [], False],
# Decorator based init=false
[dedent('''
@dataclass_transform
def create_model():
pass
@create_model(init=False)
class X:'''), [], False],
# Metaclass based init=false
[dedent('''
@dataclass_transform
class ModelMeta():
y: int
z = 5
class ModelBase(metaclass=ModelMeta):
t: int
p = 5
class X(ModelBase, init=False):'''), [], False],
]
ids = [
@@ -493,6 +517,9 @@ ids = [
"decorator_transformed",
"metaclass_transformed",
"custom_init",
"base_transformed_init_false",
"decorator_transformed_init_false",
"metaclass_transformed_init_false",
]