mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	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
					
				
					 3 changed files with 36 additions and 2 deletions
				
			
		| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
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 R:
 | 
				
			||||||
                    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…
	
	Add table
		Add a link
		
	
		Reference in a new issue