1.1 regression due to TypeDecorator copy() from Column.copy(), interferes with mutable

Issue #3950 resolved
Mike Bayer repo owner created an issue

this is a bug that exists since sqlalchemy.ext.mutable started, however it only is apparent when the type object is copied. The copy is uncommon except in the case of SchemaEventTarget, which TypeDecorator becomes in 1.1.

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
import json
from sqlalchemy.ext import mutable

Base = declarative_base()


class MyType(TypeDecorator):
    impl = Text

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value)
        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value)
        return value

data = Column(mutable.MutableDict.as_mutable(MyType))


class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)

    # works fine
    # data = data

    # fails in 1.1 because TypeDecorator is a SchemaType,
    # so Column copies the type, so the event we attached
    # to scan mapper columns can't identify that this is the "data"
    # we copied
    data = data.copy()  # as happens in declarative

e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)

s = Session(e)

a1 = A(data={"foo": "bar"})
s.add(a1)
s.commit()

a1.data["foo"] = "bat"
s.commit()

assert a1.data["foo"] == "bat"

Comments (3)

  1. Mike Bayer reporter

    Track SchemaEventTarget types in as_mutable()

    Fixed bug in :mod:sqlalchemy.ext.mutable where the :meth:.Mutable.as_mutable method would not track a type that had been copied using :meth:.TypeEngine.copy. This became more of a regression in 1.1 compared to 1.0 because the :class:.TypeDecorator class is now a subclass of :class:.SchemaEventTarget, which among other things indicates to the parent :class:.Column that the type should be copied when the :class:.Column is. These copies are common when using declarative with mixins or abstract classes.

    Change-Id: Ib04df862c58263185dbae686c548fea3e12c46f1 Fixes: #3950

    → <<cset 07b63894cb8f>>

  2. Mike Bayer reporter

    Track SchemaEventTarget types in as_mutable()

    Fixed bug in :mod:sqlalchemy.ext.mutable where the :meth:.Mutable.as_mutable method would not track a type that had been copied using :meth:.TypeEngine.copy. This became more of a regression in 1.1 compared to 1.0 because the :class:.TypeDecorator class is now a subclass of :class:.SchemaEventTarget, which among other things indicates to the parent :class:.Column that the type should be copied when the :class:.Column is. These copies are common when using declarative with mixins or abstract classes.

    Change-Id: Ib04df862c58263185dbae686c548fea3e12c46f1 Fixes: #3950 (cherry picked from commit 07b63894cb8ff9529b406f196b5d7cb9af209e9e)

    → <<cset 502a46b64e04>>

  3. Log in to comment