Skip to content

Commit

Permalink
Fix converters on frozen classes
Browse files Browse the repository at this point in the history
Fixes #76

This should be reasonably fast @Tinche?
  • Loading branch information
hynek committed Sep 5, 2016
1 parent 60017ee commit a624035
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ The third digit is only for regressions.
Changes:
^^^^^^^^

*none*
- Converts now work with frozen classes.
`#76 <https://github.com/hynek/attrs/issues/76>`_


----
Expand Down
12 changes: 9 additions & 3 deletions src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,17 +470,20 @@ def validate(inst):
a.validator(inst, a, getattr(inst, a.name))


def _convert(inst):
def _convert(inst, setattr_):
"""
Convert all attributes on *inst* that have a converter.
Uses *setattr_* to set the attributes on the class. Allows for
circumvention of frozen instances.
Leaves all exceptions through.
:param inst: Instance of a class with ``attrs`` attributes.
"""
for a in inst.__class__.__attrs_attrs__:
if a.convert is not None:
setattr(inst, a.name, a.convert(getattr(inst, a.name)))
setattr_(a.name, a.convert(getattr(inst, a.name)))


def _attrs_to_script(attrs, frozen):
Expand Down Expand Up @@ -564,7 +567,10 @@ def fmt_setter(attr_name, value):
lines.append(fmt_setter(attr_name, arg_name))

if has_convert:
lines.append("_convert(self)")
if frozen is True:
lines.append("_convert(self, _setattr)")
else:
lines.append("_convert(self, self.__setattr__)")
if attrs_to_validate: # we can skip this if there are no validators.
validators_for_globals["_config"] = _config
lines.append("if _config._run_validators is False:")
Expand Down
7 changes: 7 additions & 0 deletions tests/test_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,13 @@ def validator(inst, attr, val):
with pytest.raises(ZeroDivisionError):
C(1, 2)

def test_frozen(self):
"""
Converters circumvent immutability.
"""
C = make_class("C", {"x": attr(convert=lambda v: int(v))}, frozen=True)
C("1")


class TestValidate(object):
"""
Expand Down

0 comments on commit a624035

Please sign in to comment.