diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst index a09c28ad979158..954edc4506df1a 100644 --- a/Doc/library/dataclasses.rst +++ b/Doc/library/dataclasses.rst @@ -418,7 +418,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, decorator=dataclass) +.. 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, qualname=None, decorator=dataclass) Creates a new dataclass with name *cls_name*, fields as defined in *fields*, base classes as given in *bases*, and initialized @@ -434,6 +434,9 @@ Module contents of the dataclass is set to that value. By default, it is set to the module name of the caller. + If *qualname* is defined, the :attr:`~type.__qualname__` attribute of the dataclass + is set to that value. By default, it is set to the value passed to *cls_name*. + 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 :deco:`dataclass`. By default, the :deco:`dataclass` @@ -464,6 +467,8 @@ Module contents .. versionadded:: 3.14 Added the *decorator* parameter. + .. versionadded:: next + Added the *qualname* parameter. .. function:: replace(obj, /, **changes) diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index dbfabded2e47aa..035678d902adaf 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -1644,7 +1644,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, decorator=dataclass): + weakref_slot=False, module=None, qualname=None, decorator=dataclass): """Return a new dynamically created dataclass. The dataclass name will be 'cls_name'. 'fields' is an iterable @@ -1669,6 +1669,9 @@ class C(Base): If module parameter is defined, the '__module__' attribute of the dataclass is set to that value. + + If qualname parameter is defined, the '__qualname__' attribute of the dataclass is set + to that value. """ if namespace is None: @@ -1758,6 +1761,9 @@ def exec_body_callback(ns): if module is not None: cls.__module__ = module + if qualname: + cls.__qualname__ = qualname + # Apply the normal provided decorator. cls = decorator(cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen, diff --git a/Lib/test/test_dataclasses/__init__.py b/Lib/test/test_dataclasses/__init__.py index dcd6a3ef9abfab..2468e3e64dd621 100644 --- a/Lib/test/test_dataclasses/__init__.py +++ b/Lib/test/test_dataclasses/__init__.py @@ -5289,6 +5289,15 @@ class A: self.assertEqual(len(fs), 1) self.assertEqual(fs[0].name, 'x') + def test_makedataclass_with_qualname(self): + A = make_dataclass("A", ['a'], qualname='ClassA') + self.assertEqual(A.__qualname__, 'ClassA') + + B = make_dataclass("B", ['b'], qualname='module1.ClassB') + self.assertEqual(B.__qualname__, 'module1.ClassB') + + C = make_dataclass("C", ['c']) + self.assertEqual(C.__qualname__, 'C') class TestZeroArgumentSuperWithSlots(unittest.TestCase): def test_zero_argument_super(self): diff --git a/Misc/NEWS.d/next/Library/2026-05-18-13-43-06.gh-issue-79413.OpTXbV.rst b/Misc/NEWS.d/next/Library/2026-05-18-13-43-06.gh-issue-79413.OpTXbV.rst new file mode 100644 index 00000000000000..8d62fda8b2b67f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-18-13-43-06.gh-issue-79413.OpTXbV.rst @@ -0,0 +1,3 @@ +Update :func:`dataclasses.make_dataclass` to add a *qualname* parameter. The +*qualname* parameter will be used to set the :attr:`!__qualname__` of the +created ``dataclass``.