Skip to content

Commit c7437e2

Browse files
bpo-41747: Ensure all dataclass methods uses their parents' qualname (GH-22155)
* bpo-41747: Ensure all dataclass methods uses their parents' qualname Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent 9a1ad2c commit c7437e2

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

Lib/dataclasses.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import functools
99
import abc
1010
import _thread
11-
from types import GenericAlias
11+
from types import FunctionType, GenericAlias
1212

1313

1414
__all__ = ['dataclass',
@@ -757,12 +757,19 @@ def _get_field(cls, a_name, a_type):
757757

758758
return f
759759

760+
def _set_qualname(cls, value):
761+
# Ensure that the functions returned from _create_fn uses the proper
762+
# __qualname__ (the class they belong to).
763+
if isinstance(value, FunctionType):
764+
value.__qualname__ = f"{cls.__qualname__}.{value.__name__}"
765+
return value
760766

761767
def _set_new_attribute(cls, name, value):
762768
# Never overwrites an existing attribute. Returns True if the
763769
# attribute already exists.
764770
if name in cls.__dict__:
765771
return True
772+
_set_qualname(cls, value)
766773
setattr(cls, name, value)
767774
return False
768775

@@ -777,7 +784,7 @@ def _hash_set_none(cls, fields, globals):
777784

778785
def _hash_add(cls, fields, globals):
779786
flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
780-
return _hash_fn(flds, globals)
787+
return _set_qualname(cls, _hash_fn(flds, globals))
781788

782789
def _hash_exception(cls, fields, globals):
783790
# Raise an exception.

Lib/test/test_dataclasses.py

+24
Original file line numberDiff line numberDiff line change
@@ -1936,6 +1936,30 @@ class R:
19361936
self.assertEqual(new_sample.x, another_new_sample.x)
19371937
self.assertEqual(sample.y, another_new_sample.y)
19381938

1939+
def test_dataclasses_qualnames(self):
1940+
@dataclass(order=True, unsafe_hash=True, frozen=True)
1941+
class A:
1942+
x: int
1943+
y: int
1944+
1945+
self.assertEqual(A.__init__.__name__, "__init__")
1946+
for function in (
1947+
'__eq__',
1948+
'__lt__',
1949+
'__le__',
1950+
'__gt__',
1951+
'__ge__',
1952+
'__hash__',
1953+
'__init__',
1954+
'__repr__',
1955+
'__setattr__',
1956+
'__delattr__',
1957+
):
1958+
self.assertEqual(getattr(A, function).__qualname__, f"TestCase.test_dataclasses_qualnames.<locals>.A.{function}")
1959+
1960+
with self.assertRaisesRegex(TypeError, r"A\.__init__\(\) missing"):
1961+
A()
1962+
19391963

19401964
class TestFieldNoAnnotation(unittest.TestCase):
19411965
def test_field_without_annotation(self):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Ensure all methods that generated from :func:`dataclasses.dataclass`
2+
objects now have the proper ``__qualname__`` attribute referring to
3+
the class they belong to. Patch by Batuhan Taskaya.

0 commit comments

Comments
 (0)