diff options
author | Eric V. Smith <ericvsmith@users.noreply.github.com> | 2018-03-29 15:07:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-29 15:07:48 (GMT) |
commit | 521995205a2cb6b504fe0e39af22a81f785350a3 (patch) | |
tree | ee1401dbe4dce2be5c8e7d1a0b2343d1993df4ba /Lib | |
parent | b9e7fe38a07a16942cb65cb922c234c95e2823a0 (diff) | |
download | cpython-521995205a2cb6b504fe0e39af22a81f785350a3.zip cpython-521995205a2cb6b504fe0e39af22a81f785350a3.tar.gz cpython-521995205a2cb6b504fe0e39af22a81f785350a3.tar.bz2 |
bpo-33175: dataclasses should look up __set_name__ on class, not instance (GH-6305)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/dataclasses.py | 4 | ||||
-rwxr-xr-x | Lib/test/test_dataclasses.py | 39 |
2 files changed, 36 insertions, 7 deletions
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py index 8c197fe..bd7252c 100644 --- a/Lib/dataclasses.py +++ b/Lib/dataclasses.py @@ -248,11 +248,11 @@ class Field: # the default value, so the end result is a descriptor that had # __set_name__ called on it at the right time. def __set_name__(self, owner, name): - func = getattr(self.default, '__set_name__', None) + func = getattr(type(self.default), '__set_name__', None) if func: # There is a __set_name__ method on the descriptor, # call it. - func(owner, name) + func(self.default, owner, name) class _DataclassParams: diff --git a/Lib/test/test_dataclasses.py b/Lib/test/test_dataclasses.py index 2745eaf..5cd424c 100755 --- a/Lib/test/test_dataclasses.py +++ b/Lib/test/test_dataclasses.py @@ -2705,7 +2705,7 @@ class TestDescriptors(unittest.TestCase): # Create a descriptor. class D: def __set_name__(self, owner, name): - self.name = name + self.name = name + 'x' def __get__(self, instance, owner): if instance is not None: return 1 @@ -2716,7 +2716,7 @@ class TestDescriptors(unittest.TestCase): @dataclass class C: c: int=D() - self.assertEqual(C.c.name, 'c') + self.assertEqual(C.c.name, 'cx') # Now test with a default value and init=False, which is the # only time this is really meaningful. If not using @@ -2724,7 +2724,7 @@ class TestDescriptors(unittest.TestCase): @dataclass class C: c: int=field(default=D(), init=False) - self.assertEqual(C.c.name, 'c') + self.assertEqual(C.c.name, 'cx') self.assertEqual(C().c, 1) def test_non_descriptor(self): @@ -2733,12 +2733,41 @@ class TestDescriptors(unittest.TestCase): class D: def __set_name__(self, owner, name): - self.name = name + self.name = name + 'x' @dataclass class C: c: int=field(default=D(), init=False) - self.assertEqual(C.c.name, 'c') + self.assertEqual(C.c.name, 'cx') + + def test_lookup_on_instance(self): + # See bpo-33175. + class D: + pass + + d = D() + # Create an attribute on the instance, not type. + d.__set_name__ = Mock() + + # Make sure d.__set_name__ is not called. + @dataclass + class C: + i: int=field(default=d, init=False) + + self.assertEqual(d.__set_name__.call_count, 0) + + def test_lookup_on_class(self): + # See bpo-33175. + class D: + pass + D.__set_name__ = Mock() + + # Make sure D.__set_name__ is called. + @dataclass + class C: + i: int=field(default=D(), init=False) + + self.assertEqual(D.__set_name__.call_count, 1) if __name__ == '__main__': |