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
10 changes: 9 additions & 1 deletion Doc/library/dataclasses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ Module contents
:func:`!astuple` raises :exc:`TypeError` if *obj* is not a dataclass
instance.

.. function:: make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False, module=None)
.. function:: make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False, match_args=True, kw_only=False, slots=False, weakref_slot=False, module=None, decorator=dataclass)

Creates a new dataclass with name *cls_name*, fields as defined
in *fields*, base classes as given in *bases*, and initialized
Expand All @@ -415,6 +415,11 @@ Module contents
of the dataclass is set to that value.
By default, it is set to the module name of the caller.

The *decorator* parameter is a callable that will be used to create the dataclass.
It should take the class object as a first argument and the same keyword arguments
as :func:`@dataclass <dataclass>`. By default, the :func:`@dataclass <dataclass>`
function is used.

This function is not strictly required, because any Python
mechanism for creating a new class with :attr:`!__annotations__` can
then apply the :func:`@dataclass <dataclass>` function to convert that class to
Expand All @@ -438,6 +443,9 @@ Module contents
def add_one(self):
return self.x + 1

.. versionadded:: 3.14
Added the *decorator* parameter.

.. function:: replace(obj, /, **changes)

Creates a new object of the same type as *obj*, replacing
Expand Down
6 changes: 3 additions & 3 deletions Lib/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1550,7 +1550,7 @@ def _astuple_inner(obj, tuple_factory):
def make_dataclass(cls_name, fields, *, bases=(), namespace=None, init=True,
repr=True, eq=True, order=False, unsafe_hash=False,
frozen=False, match_args=True, kw_only=False, slots=False,
weakref_slot=False, module=None):
weakref_slot=False, module=None, decorator=dataclass):
"""Return a new dynamically created dataclass.

The dataclass name will be 'cls_name'. 'fields' is an iterable
Expand Down Expand Up @@ -1630,8 +1630,8 @@ def exec_body_callback(ns):
if module is not None:
cls.__module__ = module

# Apply the normal decorator.
return dataclass(cls, init=init, repr=repr, eq=eq, order=order,
# Apply the normal provided decorator.
return decorator(cls, init=init, repr=repr, eq=eq, order=order,
unsafe_hash=unsafe_hash, frozen=frozen,
match_args=match_args, kw_only=kw_only, slots=slots,
weakref_slot=weakref_slot)
Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_dataclasses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4317,6 +4317,23 @@ def test_funny_class_names_names(self):
C = make_dataclass(classname, ['a', 'b'])
self.assertEqual(C.__name__, classname)

def test_dataclass_decorator_default(self):
C = make_dataclass('C', [('x', int)], decorator=dataclass)
c = C(10)
self.assertEqual(c.x, 10)

def test_dataclass_custom_decorator(self):
def custom_dataclass(cls, *args, **kwargs):
dc = dataclass(cls, *args, **kwargs)
dc.__custom__ = True
return dc

C = make_dataclass('C', [('x', int)], decorator=custom_dataclass)
c = C(10)
self.assertEqual(c.x, 10)
self.assertEqual(c.__custom__, True)


class TestReplace(unittest.TestCase):
def test(self):
@dataclass(frozen=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add ``decorator`` parameter to :func:`dataclasses.make_dataclass`
to customize the functional creation of dataclasses.
Loading