Repository: python-attrs/attrs (python)

Issue:
Exception when using auto_attribs and a attribute named property
Given a class like:

```python
@attr.s(auto_attribs=True)
class Foo:

    property: str
    other: str
```

Attrs is raising an exception:

```
Traceback (most recent call last):
  File "f.py", line 13, in <module>
    @attr.s(auto_attribs=True)
  File "/usr/local/lib/python3.6/site-packages/attr/_make.py", line 729, in wrap
    builder = _ClassBuilder(cls, these, slots, frozen, auto_attribs)
  File "/usr/local/lib/python3.6/site-packages/attr/_make.py", line 409, in __init__
    cls, these, auto_attribs
  File "/usr/local/lib/python3.6/site-packages/attr/_make.py", line 354, in _transform_attrs
    AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
  File "/usr/local/lib/python3.6/site-packages/attr/_make.py", line 220, in _make_attr_tuple_class
    eval(compile("\n".join(attr_class_template), "", "exec"), globs)
  File "", line 1, in <module>
  File "", line 4, in BreaksAttributes
TypeError: 'property' object is not callable
```

What's odd here, is that it works fine as long as property is the *last* item in the class, e.g.:

```python
@attr.s(auto_attribs=True)
class Foo:

    other: str
    property: str
```

this works fine and doesn't raise an error.

Pull request description:
Allow attributes to be called property and itemgetter
Fixes #429 by aliasing `property` and `itemgetter` to private names.

Patch:
diff --git a/changelog.d/430.change.rst b/changelog.d/430.change.rst
new file mode 100644
index 0000000..f4ac16f
--- /dev/null
+++ b/changelog.d/430.change.rst
@@ -0,0 +1,1 @@
+Attributes can be named ``property`` and ``itemgetter`` now.
diff --git a/src/attr/_make.py b/src/attr/_make.py
index ecb668b..4a0095f 100644
--- a/src/attr/_make.py
+++ b/src/attr/_make.py
@@ -31,7 +31,9 @@ from .exceptions import (
 _obj_setattr = object.__setattr__
 _init_converter_pat = "__attr_converter_{}"
 _init_factory_pat = "__attr_factory_{}"
-_tuple_property_pat = "    {attr_name} = property(itemgetter({index}))"
+_tuple_property_pat = (
+    "    {attr_name} = _attrs_property(_attrs_itemgetter({index}))"
+)
 _classvar_prefixes = ("typing.ClassVar", "t.ClassVar", "ClassVar")
 # we don't use a double-underscore prefix because that triggers
 # name mangling when trying to create a slot for the field
@@ -243,8 +245,9 @@ def _make_attr_tuple_class(cls_name, attr_names):
             )
     else:
         attr_class_template.append("    pass")
-    globs = {"itemgetter": itemgetter}
+    globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
     eval(compile("\n".join(attr_class_template), "", "exec"), globs)
+
     return globs[attr_class_name]
 
 


Test patch:
diff --git a/tests/test_dark_magic.py b/tests/test_dark_magic.py
index 988d4a9..4c93b3f 100644
--- a/tests/test_dark_magic.py
+++ b/tests/test_dark_magic.py
@@ -482,3 +482,18 @@ class TestDarkMagic(object):
 
             with pytest.raises(FrozenInstanceError):
                 i.b = "3"
+
+    def test_tuple_class_aliasing(self):
+        """
+        itemgetter and property are legal attribute names.
+        """
+
+        @attr.s
+        class C(object):
+            property = attr.ib()
+            itemgetter = attr.ib()
+            x = attr.ib()
+
+        assert "property" == attr.fields(C).property.name
+        assert "itemgetter" == attr.fields(C).itemgetter.name
+        assert "x" == attr.fields(C).x.name