Repository: python-attrs/attrs
Pull request #747 (2021-01-08 10:40:14)

Fix: TypeError when using properties, super(), and slots=True (#652)
# Pull Request Check List

This is just a friendly reminder about the most common mistakes.  Please make sure that you tick all boxes.  But please read our [contribution guide](https://www.attrs.org/en/latest/contributing.html) at least once, it will save you unnecessary review cycles!

If an item doesn't apply to your pull request, **check it anyway** to make it apparent that there's nothing left to do.  If your pull request is a documentation fix or a trivial typo, feel free to delete the whole thing.

- [x] Added **tests** for changed code.
- [x] New features have been added to our [Hypothesis testing strategy](https://github.com/python-attrs/attrs/blob/master/tests/strategies.py). [N/A]
- [x] Changes or additions to public APIs are reflected in our type stubs (files ending in ``.pyi``). [N/A]
    - [x] ...and used in the stub test file `tests/typing_example.py`. [N/A]
- [x] Updated **documentation** for changed code. [N/A]
    - [x] New functions/classes have to be added to `docs/api.rst` by hand. [N/A]
    - [x] Changes to the signature of `@attr.s()` have to be added by hand too. [N/A]
    - [x] Changed/added classes/methods/functions have appropriate `versionadded`, `versionchanged`, or `deprecated` [directives](http://www.sphinx-doc.org/en/stable/markup/para.html#directive-versionadded).  Find the appropriate next version in our [``__init__.py``](https://github.com/python-attrs/attrs/blob/master/src/attr/__init__.py) file. [N/A]
- [x] Documentation in `.rst` files is written using [semantic newlines](https://rhodesmill.org/brandon/2012/one-sentence-per-line/).
- [x] Changes (and possible deprecations) have news fragments in [`changelog.d`](https://github.com/python-attrs/attrs/blob/master/changelog.d).

If you have *any* questions to *any* of the points above, just **submit and ask**!  This checklist is here to *help* you, not to deter you from contributing!



Patch:
diff --git a/changelog.d/747.change.rst b/changelog.d/747.change.rst
new file mode 100644
index 0000000..95b0b83
--- /dev/null
+++ b/changelog.d/747.change.rst
@@ -0,0 +1,1 @@
+Fixed ``TypeError`` when using properties, ``super()``, and ``slots=True``.
diff --git a/src/attr/_make.py b/src/attr/_make.py
index 255cf1a..09a41b1 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -795,6 +795,10 @@ class _ClassBuilder(object):
                 # Class- and staticmethods hide their functions inside.
                 # These might need to be rewritten as well.
                 closure_cells = getattr(item.__func__, "__closure__", None)
+            elif isinstance(item, property):
+                # Workaround for property `super()` shortcut (PY3-only).
+                # There is no universal way for other descriptors.
+                closure_cells = getattr(item.fget, "__closure__", None)
             else:
                 closure_cells = getattr(item, "__closure__", None)
 


Test patch:
diff --git a/tests/test_slots.py b/tests/test_slots.py
index d5106ff..df1d56c 100644
--- a/tests/test_slots.py
+++ b/tests/test_slots.py
@@ -689,3 +689,50 @@ class TestPickle(object):
         """
         assert None is not getattr(cls, "__getstate__", None)
         assert None is not getattr(cls, "__setstate__", None)
+
+
+def test_slots_super_property_get():
+    """
+    In Python 2/3: the `super(self.__class__, self)`.
+    """
+
+    @attr.s(slots=True)
+    class A(object):
+        x = attr.ib()
+
+        @property
+        def f(self):
+            return self.x
+
+    @attr.s(slots=True)
+    class B(A):
+        @property
+        def f(self):
+            return super(B, self).f ** 2
+
+    assert B(11).f == 121
+    assert B(17).f == 289
+
+
+@pytest.mark.skipif(PY2, reason="shortcut super() is PY3-only.")
+def test_slots_super_property_get_shurtcut():
+    """
+    In Python 3, the `super()` shortcut is allowed.
+    """
+
+    @attr.s(slots=True)
+    class A(object):
+        x = attr.ib()
+
+        @property
+        def f(self):
+            return self.x
+
+    @attr.s(slots=True)
+    class B(A):
+        @property
+        def f(self):
+            return super().f ** 2
+
+    assert B(11).f == 121
+    assert B(17).f == 289