From 3cbbd470b752e0ab27bc6c6bd89f9895f6157c34 Mon Sep 17 00:00:00 2001 From: "Tim.Mitchell" Date: Tue, 5 Mar 2024 15:18:15 +1300 Subject: [PATCH] Fix bug with read-only implementations of attributes on dataclasses. --- pure_interface/interface.py | 11 ++++++++++- tests/test_dataclass_support.py | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pure_interface/interface.py b/pure_interface/interface.py index 18c0640..4cce0cd 100644 --- a/pure_interface/interface.py +++ b/pure_interface/interface.py @@ -402,11 +402,20 @@ def _ensure_everything_is_abstract(attributes): return namespace, functions, interface_method_signatures, interface_attribute_names +def _readonly_attribute(name, namespace): + # if the attribute is a property with a getter but no setter then it is read-only + prop = namespace.get(name) + if isinstance(prop, property): + if prop.fset is None: + return True + return False + + def _ensure_annotations(names, namespace): # annotations need to be kept in order, add base-class names first annotations = {} for name in names: - if name not in annotations: + if name not in annotations and not _readonly_attribute(name, namespace): annotations[name] = Any annotations.update(namespace.get('__annotations__', {})) namespace['__annotations__'] = annotations diff --git a/tests/test_dataclass_support.py b/tests/test_dataclass_support.py index 46376aa..5c27309 100644 --- a/tests/test_dataclass_support.py +++ b/tests/test_dataclass_support.py @@ -53,3 +53,19 @@ def foo(self): f = Foo(a=1, b='two') self.assertEqual(1, f.a) self.assertEqual('two', f.b) + + def test_read_only_attr(self): + @dataclass + class RoFoo(IFoo): + c: int + + @property + def b(self): + return 'str' + + def foo(self): + return 'a={}, b={}, c={}'.format(self.a, self.b, self.c) + + f = RoFoo(a=1, c=3) + self.assertEqual(1, f.a) + self.assertEqual('str', f.b)