From: Mike Bayer Date: Sat, 22 Sep 2007 15:55:02 +0000 (+0000) Subject: - added 'comparator' keyword argument to PickleType. By default, "mutable" X-Git-Tag: rel_0_4beta6~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7f6bf93da869a5b59c53d0d10a50da3c23c4b738;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - added 'comparator' keyword argument to PickleType. By default, "mutable" PickleType does a "deep compare" of objects using their dumps() representation. But this doesn't work for dictionaries. Pickled objects which provide an adequate __eq__() implementation can be set up with "PickleType(comparator=operator.eq)" [ticket:560] --- diff --git a/CHANGES b/CHANGES index 00b01f4a36..c35978f42b 100644 --- a/CHANGES +++ b/CHANGES @@ -22,6 +22,12 @@ CHANGES insert/update statement compilation process in terms of the column names present but not the values for those columns. Produces more consistent execute/executemany behavior, simplifies things a bit internally. + +- added 'comparator' keyword argument to PickleType. By default, "mutable" + PickleType does a "deep compare" of objects using their dumps() representation. + But this doesn't work for dictionaries. Pickled objects which provide an + adequate __eq__() implementation can be set up with "PickleType(comparator=operator.eq)" + [ticket:560] - Fixed reflection of the empty string for mysql enums. diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 833d2cf159..71b4bbec1b 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -421,10 +421,11 @@ class Binary(TypeEngine): class PickleType(MutableType, TypeDecorator): impl = Binary - def __init__(self, protocol=pickle.HIGHEST_PROTOCOL, pickler=None, mutable=True): + def __init__(self, protocol=pickle.HIGHEST_PROTOCOL, pickler=None, mutable=True, comparator=None): self.protocol = protocol self.pickler = pickler or pickle self.mutable = mutable + self.comparator = comparator super(PickleType, self).__init__() def bind_processor(self, dialect): @@ -455,7 +456,9 @@ class PickleType(MutableType, TypeDecorator): return value def compare_values(self, x, y): - if self.mutable: + if self.comparator: + return self.comparator(x, y) + elif self.mutable: return self.pickler.dumps(x, self.protocol) == self.pickler.dumps(y, self.protocol) else: return x is y diff --git a/test/orm/unitofwork.py b/test/orm/unitofwork.py index c202abf99b..b7bff2d787 100644 --- a/test/orm/unitofwork.py +++ b/test/orm/unitofwork.py @@ -301,7 +301,6 @@ class MutableTypesTest(ORMTest): ), ]) - def test_nocomparison(self): """test that types marked as MutableType get changes detected on them when the type has no __eq__ method""" class Foo(object):pass @@ -352,7 +351,49 @@ class MutableTypesTest(ORMTest): def go(): Session.commit() self.assert_sql_count(testbase.db, go, 0) + +class MutableTypesTest2(ORMTest): + def define_tables(self, metadata): + global table + import operator + table = Table('mutabletest', metadata, + Column('id', Integer, Sequence('mutableidseq', optional=True), primary_key=True), + Column('data', PickleType(comparator=operator.eq)), + ) + + def test_dicts(self): + """dictionaries dont pickle the same way twice, sigh.""" + + class Foo(object):pass + mapper(Foo, table) + f1 = Foo() + f1.data = [{'personne': {'nom': u'Smith', 'pers_id': 1, 'prenom': u'john', 'civilite': u'Mr', \ + 'int_3': False, 'int_2': False, 'int_1': u'23', 'VenSoir': True, 'str_1': u'Test', \ + 'SamMidi': False, 'str_2': u'chien', 'DimMidi': False, 'SamSoir': True, 'SamAcc': False}}] + + Session.commit() + def go(): + Session.commit() + self.assert_sql_count(testbase.db, go, 0) + + f1.data = [{'personne': {'nom': u'Smith', 'pers_id': 1, 'prenom': u'john', 'civilite': u'Mr', \ + 'int_3': False, 'int_2': False, 'int_1': u'23', 'VenSoir': True, 'str_1': u'Test', \ + 'SamMidi': False, 'str_2': u'chien', 'DimMidi': False, 'SamSoir': True, 'SamAcc': False}}] + + def go(): + Session.commit() + self.assert_sql_count(testbase.db, go, 0) + + f1.data[0]['personne']['VenSoir']= False + def go(): + Session.commit() + self.assert_sql_count(testbase.db, go, 1) + Session.clear() + f = Session.query(Foo).get(f1.id) + assert f.data == [{'personne': {'nom': u'Smith', 'pers_id': 1, 'prenom': u'john', 'civilite': u'Mr', \ + 'int_3': False, 'int_2': False, 'int_1': u'23', 'VenSoir': False, 'str_1': u'Test', \ + 'SamMidi': False, 'str_2': u'chien', 'DimMidi': False, 'SamSoir': True, 'SamAcc': False}}] class PKTest(ORMTest): def define_tables(self, metadata):