[Sqlalchemy-tickets] Issue #3853: MutableSet isn't change aware on bitwise operators (zzzeek/sqlalc
Brought to you by:
zzzeek
From: Daniel K. <iss...@bi...> - 2016-11-17 18:06:50
|
New issue 3853: MutableSet isn't change aware on bitwise operators https://bitbucket.org/zzzeek/sqlalchemy/issues/3853/mutableset-isnt-change-aware-on-bitwise Daniel Kolsoi: Python sets support common set operations as bitwise operators such as &=, |=, ^=, -=. The MutableSet class seems to fully support these operations as full methods (.intersection, .union, ...) but not bitwise operators. This is unexpected since the bitwise operators do in fact modify the underlying set(due to inheriting from set), but since the .changed() method is not called by MutableSet, sqlalchemy is never notified that the data has been modified. This leads to the possibility of having a mutable set column which is modified locally but does not get updated on commit or flush. For example, ``` #!python from sqlalchemy.ext.mutable import MutableSet from sqlalchemy.types import TypeDecorator, UnicodeText class _JSONEncodedSet(TypeDecorator): impl = UnicodeText def process_bind_param(self, value, dialect): if value is not None: value = json.dumps(list(value)) return value def process_result_value(self, value, dialect): if value is not None: value = set(json.loads(value)) return value JSONEncodedSet = MutableSet.as_mutable(_JSONEncodedSet) from sqlalchemy.ext.declarative import declarative_base BaseModel = declarative_base() class MyModel(BaseModel): json_set = Column(JSONEncodedSet) from sqlalchemy.orm import scoped_session, sessionmaker from zope.sqlalchemy import ZopeTransactionExtension session = scoped_session(sessionmaker(extension=ZopeTransactionExtension())) session.add(MyModel(json_set={1, 2, 3})) session.flush() model = session.query(MyModel).first() model.json_set &= {1, 3} session.flush() del model model = session.query(MyModel).first() assert model.json_set == {1, 3} # AssertionError ``` Tested in SqlAlchemy 1.1.3, Sqlite. |