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>
This commit is contained in:
parent
9a1ad2cf02
commit
c7437e2c02
|
@ -8,7 +8,7 @@ import builtins
|
||||||
import functools
|
import functools
|
||||||
import abc
|
import abc
|
||||||
import _thread
|
import _thread
|
||||||
from types import GenericAlias
|
from types import FunctionType, GenericAlias
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['dataclass',
|
__all__ = ['dataclass',
|
||||||
|
@ -757,12 +757,19 @@ def _get_field(cls, a_name, a_type):
|
||||||
|
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
def _set_qualname(cls, value):
|
||||||
|
# Ensure that the functions returned from _create_fn uses the proper
|
||||||
|
# __qualname__ (the class they belong to).
|
||||||
|
if isinstance(value, FunctionType):
|
||||||
|
value.__qualname__ = f"{cls.__qualname__}.{value.__name__}"
|
||||||
|
return value
|
||||||
|
|
||||||
def _set_new_attribute(cls, name, value):
|
def _set_new_attribute(cls, name, value):
|
||||||
# Never overwrites an existing attribute. Returns True if the
|
# Never overwrites an existing attribute. Returns True if the
|
||||||
# attribute already exists.
|
# attribute already exists.
|
||||||
if name in cls.__dict__:
|
if name in cls.__dict__:
|
||||||
return True
|
return True
|
||||||
|
_set_qualname(cls, value)
|
||||||
setattr(cls, name, value)
|
setattr(cls, name, value)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -777,7 +784,7 @@ def _hash_set_none(cls, fields, globals):
|
||||||
|
|
||||||
def _hash_add(cls, fields, globals):
|
def _hash_add(cls, fields, globals):
|
||||||
flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
|
flds = [f for f in fields if (f.compare if f.hash is None else f.hash)]
|
||||||
return _hash_fn(flds, globals)
|
return _set_qualname(cls, _hash_fn(flds, globals))
|
||||||
|
|
||||||
def _hash_exception(cls, fields, globals):
|
def _hash_exception(cls, fields, globals):
|
||||||
# Raise an exception.
|
# Raise an exception.
|
||||||
|
|
|
@ -1936,6 +1936,30 @@ class TestCase(unittest.TestCase):
|
||||||
self.assertEqual(new_sample.x, another_new_sample.x)
|
self.assertEqual(new_sample.x, another_new_sample.x)
|
||||||
self.assertEqual(sample.y, another_new_sample.y)
|
self.assertEqual(sample.y, another_new_sample.y)
|
||||||
|
|
||||||
|
def test_dataclasses_qualnames(self):
|
||||||
|
@dataclass(order=True, unsafe_hash=True, frozen=True)
|
||||||
|
class A:
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
|
||||||
|
self.assertEqual(A.__init__.__name__, "__init__")
|
||||||
|
for function in (
|
||||||
|
'__eq__',
|
||||||
|
'__lt__',
|
||||||
|
'__le__',
|
||||||
|
'__gt__',
|
||||||
|
'__ge__',
|
||||||
|
'__hash__',
|
||||||
|
'__init__',
|
||||||
|
'__repr__',
|
||||||
|
'__setattr__',
|
||||||
|
'__delattr__',
|
||||||
|
):
|
||||||
|
self.assertEqual(getattr(A, function).__qualname__, f"TestCase.test_dataclasses_qualnames.<locals>.A.{function}")
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, r"A\.__init__\(\) missing"):
|
||||||
|
A()
|
||||||
|
|
||||||
|
|
||||||
class TestFieldNoAnnotation(unittest.TestCase):
|
class TestFieldNoAnnotation(unittest.TestCase):
|
||||||
def test_field_without_annotation(self):
|
def test_field_without_annotation(self):
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Ensure all methods that generated from :func:`dataclasses.dataclass`
|
||||||
|
objects now have the proper ``__qualname__`` attribute referring to
|
||||||
|
the class they belong to. Patch by Batuhan Taskaya.
|
Loading…
Reference in New Issue