Split dataclass and dataclass_transform logic

This commit is contained in:
Eric Masseran
2025-08-29 18:54:14 +02:00
parent 4ea7981680
commit 0f35a1b18b

View File

@@ -596,16 +596,49 @@ def _random_choice(sequences):
def _dataclass(value, arguments, callback): def _dataclass(value, arguments, callback):
""" """
Decorator entry points for dataclass, dataclass_transform and attrs. Decorator entry points for dataclass.
1. dataclass-like decorator instantiation from a dataclass_transform decorator 1. dataclass decorator declaration with parameters
2. dataclass_transform decorator declaration with parameters 2. dataclass semantics on a class from a dataclass(-like) decorator
3. dataclass(-like) decorator declaration with parameters
4. dataclass(-like) semantics on a class from a dataclass(-like) decorator
""" """
for c in _follow_param(value.inference_state, arguments, 0): for c in _follow_param(value.inference_state, arguments, 0):
if c.is_class(): if c.is_class():
# Declare dataclass semantics on a class from a dataclass decorator
should_generate_init = (
# Customized decorator, init may be disabled
value.init_param_mode
if isinstance(value, DataclassDecorator)
# Bare dataclass decorator, always with init mode
else True
)
return ValueSet([DataclassWrapper(c, should_generate_init)])
else:
# @dataclass(init=False)
# dataclass decorator customization
return ValueSet(
[
DataclassDecorator(
value,
arguments=arguments,
default_init=True,
)
]
)
return NO_VALUES
def _dataclass_transform(value, arguments, callback):
"""
Decorator entry points for dataclass_transform.
1. dataclass-like decorator instantiation from a dataclass_transform decorator
2. dataclass_transform decorator declaration with parameters
3. dataclass-like decorator declaration with parameters
4. dataclass-like semantics on a class from a dataclass-like decorator
"""
for c in _follow_param(value.inference_state, arguments, 0):
if c.is_class():
is_dataclass_transform = ( is_dataclass_transform = (
value.name.string_name == "dataclass_transform" value.name.string_name == "dataclass_transform"
# The decorator function from dataclass_transform acting as the # The decorator function from dataclass_transform acting as the
@@ -620,15 +653,9 @@ def _dataclass(value, arguments, callback):
# Declare base class # Declare base class
return ValueSet([DataclassTransformer(c)]) return ValueSet([DataclassTransformer(c)])
else: else:
# Declare dataclass(-like) semantics on a class from a # Declare dataclass-like semantics on a class from a
# dataclass(-like) decorator # dataclass-like decorator
should_generate_init = ( should_generate_init = value.init_param_mode
# Customized decorator, init may be disabled
value.init_param_mode
if isinstance(value, DataclassDecorator)
# Bare dataclass decorator, always with init mode
else True
)
return ValueSet([DataclassWrapper(c, should_generate_init)]) return ValueSet([DataclassWrapper(c, should_generate_init)])
elif c.is_function(): elif c.is_function():
# dataclass-like decorator instantiation: # dataclass-like decorator instantiation:
@@ -644,12 +671,10 @@ def _dataclass(value, arguments, callback):
] ]
) )
elif ( elif (
# @dataclass(init=False)
value.name.string_name != "dataclass_transform"
# @dataclass_transform # @dataclass_transform
# def create_model(): pass # def create_model(): pass
# @create_model(init=...) # @create_model(init=...)
or isinstance(value, Decoratee) isinstance(value, Decoratee)
): ):
# dataclass (or like) decorator customization # dataclass (or like) decorator customization
return ValueSet( return ValueSet(
@@ -657,11 +682,7 @@ def _dataclass(value, arguments, callback):
DataclassDecorator( DataclassDecorator(
value, value,
arguments=arguments, arguments=arguments,
default_init=( default_init=value._wrapped_value.init_param_mode,
value._wrapped_value.init_param_mode
if isinstance(value, Decoratee)
else True
),
) )
] ]
) )
@@ -820,11 +841,11 @@ _implemented = {
# adding logs for infering stuff, so we can safely ignore it. # adding logs for infering stuff, so we can safely ignore it.
'runtime_checkable': lambda value, arguments, callback: NO_VALUES, 'runtime_checkable': lambda value, arguments, callback: NO_VALUES,
# Python 3.11+ # Python 3.11+
'dataclass_transform': _dataclass, 'dataclass_transform': _dataclass_transform,
}, },
'typing_extensions': { 'typing_extensions': {
# Python <3.11 # Python <3.11
'dataclass_transform': _dataclass, 'dataclass_transform': _dataclass_transform,
}, },
'dataclasses': { 'dataclasses': {
# For now this works at least better than Jedi trying to understand it. # For now this works at least better than Jedi trying to understand it.