diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 621d90765618a19..37ae9de77281ef5 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,7 +24,8 @@ Deprecations: Changes: ^^^^^^^^ -*none* +- Fix *str* on Python 2 when ``slots=True``. + `#198 `_ ---- diff --git a/src/attr/_make.py b/src/attr/_make.py index 260629d0f78687d..7f70b8c4c5b58d5 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -343,9 +343,7 @@ def wrap(cls): # Can't compare function objects because Python 2 is terrible. :( effectively_frozen = _has_frozen_superclass(cls) or frozen if repr is True: - cls = _add_repr(cls, ns=repr_ns) - if str is True: - cls.__str__ = cls.__repr__ + cls = _add_repr(cls, ns=repr_ns, str=str) if cmp is True: cls = _add_cmp(cls) @@ -516,9 +514,9 @@ def ge(self, other): return cls -def _add_repr(cls, ns=None, attrs=None): +def _add_repr(cls, ns=None, attrs=None, str=False): """ - Add a repr method to *cls*. + Add a repr method to *cls*. If *str* is True, also add __str__. """ if attrs is None: attrs = [a for a in cls.__attrs_attrs__ if a.repr] @@ -543,6 +541,8 @@ def repr_(self): for a in attrs) ) cls.__repr__ = repr_ + if str is True: + cls.__str__ = repr_ return cls diff --git a/tests/test_dunders.py b/tests/test_dunders.py index ff542d5e866203e..0ccbc91c1ee4ded 100644 --- a/tests/test_dunders.py +++ b/tests/test_dunders.py @@ -198,15 +198,15 @@ class C(object): assert "C(_x=42)" == repr(i) - @pytest.mark.parametrize("add_str", [True, False]) - def test_str(self, add_str): + @given(add_str=booleans(), slots=booleans()) + def test_str(self, add_str, slots): """ If str is True, it returns the same as repr. This only makes sense when subclassing a class with an poor __str__ (like Exceptions). """ - @attributes(str=add_str) + @attributes(str=add_str, slots=slots) class Error(Exception): x = attr()