Mutable fails to track changes in certain conditions

Issue #2997 resolved
Vsevolod Solovyov created an issue

Hello, this is a code that illustrates my problem:

>>> product.attrdata
{'key': 1}
>>> product.attrdata = product.attrdata or {}
>>> product.attrdata['key'] = 20
>>> db_session.commit()
>>> db_session.refresh(product)
>>> product.attrdata
{'key': 1}

>>> product.attrdata['key'] = 20
>>> db_session.commit()
>>> db_session.refresh(product)
>>> product.attrdata
{'key': 20}

product.attrdata is a MutableDict. As a first step, I've found that Mutable.changed() fails:

    def changed(self):
        for parent, key in self._parents.items():
            flag_modified(parent, key)

Because self._parents are empty. That's because in MutableBase.set(), when I do product.attrdata = product.attrdata:

        def set(target, value, oldvalue, initiator):
            if not isinstance(value, cls):
                value = cls.coerce(key, value)
            if value is not None:
                value._parents[target.obj()] = key
            if isinstance(oldvalue, cls):
                oldvalue._parents.pop(target.obj(), None)
            return value

value is oldvalue and parent gets popped after it was set. If I switch these two if's, then Mutable.changed() will call flag_modified(), but it won't flag properly it anyway (I didn't dig much further and don't have a patch to fix a problem).

Is it a bug or I shouldn't do things like product.attrdata = product.attrdata in the first place?

SQLAlchemy version 0.9.3

Comments (6)

  1. Mike Bayer repo owner

    ok it seems like if set() just does "if value is oldvalue: return" that would fix it right?

  2. Mike Bayer repo owner
    • Fixed bug in mutable extension as well as :func:.attributes.flag_modified where the change event would not be propagated if the attribute had been reassigned to itself. fixes #2997

    → <<cset b9a2b58dd747>>

  3. Mike Bayer repo owner
    • Fixed bug in mutable extension as well as :func:.attributes.flag_modified where the change event would not be propagated if the attribute had been reassigned to itself. fixes #2997

    Conflicts: lib/sqlalchemy/orm/state.py test/orm/test_attributes.py

    → <<cset 66d090be9cf0>>

  4. Mike Bayer repo owner

    this is in 0.8 also. needed a little more than just that one change (was actually two bugs).

  5. Log in to comment