diff --git a/changelog.d/1606.change.md b/changelog.d/1606.change.md new file mode 100644 index 000000000..517ac446f --- /dev/null +++ b/changelog.d/1606.change.md @@ -0,0 +1 @@ +The dunder methods of `attrs.evolve()` aren't mangled anymore. diff --git a/src/attr/_make.py b/src/attr/_make.py index c7cf3642e..afbca4635 100644 --- a/src/attr/_make.py +++ b/src/attr/_make.py @@ -1108,7 +1108,11 @@ def _attach_init(cls_dict, globs): return self def add_replace(self): - self._cls_dict["__replace__"] = self._add_method_dunders(evolve) + # We create a local `evolve` proxy because it gets modified in place. + def __replace__(*args, **changes): + return evolve(*args, **changes) + + self._cls_dict["__replace__"] = self._add_method_dunders(__replace__) return self def add_match_args(self): diff --git a/tests/test_functional.py b/tests/test_functional.py index b8dfa4593..9a7a1fd86 100644 --- a/tests/test_functional.py +++ b/tests/test_functional.py @@ -816,3 +816,16 @@ def test_invalid_field_name(self): with pytest.raises(TypeError): copy.replace(inst, z=42) + + def test_is_not_evolve(self): + """ + __replace__ is not the same as attrs.evolve. + + Regression test for #1606. + """ + inst = C1(1, 2) + + assert "" == str( + inst.__replace__ + ) + assert str(attr.evolve).startswith("