Skip to content

Commit

Permalink
Revert "Recursively evolve nested attrs classes (#759)"
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek committed May 6, 2021
1 parent 24a2c1e commit ee549ea
Show file tree
Hide file tree
Showing 3 changed files with 2 additions and 70 deletions.
21 changes: 0 additions & 21 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -618,27 +618,6 @@ In Clojure that function is called `assoc <https://clojuredocs.org/clojure.core/
>>> i1 == i2
False

This functions also works for nested ``attrs`` classes.
Pass a (possibly nested) dictionary with changes for an attribute:

.. doctest::

>>> @attr.s(frozen=True)
... class Child(object):
... x = attr.ib()
... y = attr.ib()
>>> @attr.s(frozen=True)
... class Parent(object):
... child = attr.ib()
>>> i1 = Parent(Child(1, 2))
>>> i1
Parent(child=Child(x=1, y=2))
>>> i2 = attr.evolve(i1, child={"y": 3})
>>> i2
Parent(child=Child(x=1, y=3))
>>> i1 == i2, i1.child == i2.child
(False, False)


Other Goodies
-------------
Expand Down
10 changes: 2 additions & 8 deletions src/attr/_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,7 @@ def evolve(inst, **changes):
Create a new instance, based on *inst* with *changes* applied.
:param inst: Instance of a class with ``attrs`` attributes.
:param changes: Keyword changes in the new copy. Nested ``attrs`` classes
can be updated by passing (nested) dicts of values.
:param changes: Keyword changes in the new copy.
:return: A copy of inst with *changes* incorporated.
Expand All @@ -338,13 +337,8 @@ def evolve(inst, **changes):
continue
attr_name = a.name # To deal with private attributes.
init_name = attr_name if attr_name[0] != "_" else attr_name[1:]
value = getattr(inst, attr_name)
if init_name not in changes:
# Add original value to changes
changes[init_name] = value
elif has(value):
# Evolve nested attrs classes
changes[init_name] = evolve(value, **changes[init_name])
changes[init_name] = getattr(inst, attr_name)

return cls(**changes)

Expand Down
41 changes: 0 additions & 41 deletions tests/test_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,44 +597,3 @@ class C(object):
b = attr.ib(init=False, default=0)

assert evolve(C(1), a=2).a == 2

def test_recursive(self):
"""
evolve() recursively evolves nested attrs classes when a dict is
passed for an attribute.
"""

@attr.s
class N2(object):
e = attr.ib(type=int)

@attr.s
class N1(object):
c = attr.ib(type=N2)
d = attr.ib(type=int)

@attr.s
class C(object):
a = attr.ib(type=N1)
b = attr.ib(type=int)

c1 = C(N1(N2(1), 2), 3)
c2 = evolve(c1, a={"c": {"e": 23}}, b=42)

assert c2 == C(N1(N2(23), 2), 42)

def test_recursive_dict_val(self):
"""
evolve() only attempts recursion when the current value is an ``attrs``
class. Dictionaries as values can be replaced like any other value.
"""

@attr.s
class C(object):
a = attr.ib(type=dict)
b = attr.ib(type=int)

c1 = C({"spam": 1}, 2)
c2 = evolve(c1, a={"eggs": 2}, b=42)

assert c2 == C({"eggs": 2}, 42)

0 comments on commit ee549ea

Please sign in to comment.