Huh. That is odd numpy behavior. Thanks for the recipe. On Tuesday, November 19, 2013 8:35:35 PM UTC-5, Michael Bayer wrote: > > heh, this is actually some dumb numpy thing, check this out: > > >>> from numpy.ma.core import exp > >>> x = exp(1.0) > >>> a = x == x > >>> a > True > >>> a is True > False > >>> > > there’s your problem, the recipe fixes if you just say this: > > class InexactFloat(TypeDecorator): > impl = Float > > def compare_values(self, x, y): > return bool(x == y) > > > > > On Nov 19, 2013, at 8:30 PM, Michael Bayer > <mik...@zzzcomputing.com<javascript:>> > wrote: > > > On Nov 19, 2013, at 8:10 PM, Seth P <spad...@gmail.com <javascript:>> > wrote: > > I have an issue where, I believe due to floating-point representation > issues, reassigning the same value to a floating-point field causes > SQLAlchemy to think the value has been modified, and therefore emits a > gratuitous UPDATE. (This is particularly problematic when using the > versioning mixin, > http://docs.sqlalchemy.org/en/rel_0_8/orm/examples.html?highlight=versioned.) > This doesn't happen all the time, e.g. in the example below the problem > disappears if exp is imported from math rather than from numpy.ma.core. > Am I doing something wrong? If not, is there a way to tell SQLAlchemy that > a particular Float column (or even all Float columns) should not be > considered modified if the new and old values differ by less than some > threshold? Is there a way to provide a custom comparison function used for > this testing? Apologies if I missed something about this in the docs. > > > well floating points are an inexact representation, so you are hitting > that issue. If you used Numeric() instead, the floats would be coerced to > Decimal objects on the Python side, these don’t perform as well as floats > but are an exact, immutable representation - but you still can have > variability in how these come back from SQLite. > > You can in fact change the comparison function used by the unit of work to > compare for a change, just use a TypeDecorator: > > class InexactFloat(TypeDecorator): > impl = Float > > def compare_values(self, x, y): > return round(x) == round(y) # or whatever > > class A(Base): > __tablename__ = 'a' > id = Column(Integer, primary_key=True) > value = Column(InexactFloat) > > > > > > > from sqlalchemy import Column, Integer, Float, create_engine > from sqlalchemy.ext.declarative import declarative_base > from sqlalchemy.orm import create_session > from numpy.ma.core import exp > > sqlite = 'sqlite:///C:\\temp1.db' > engine = create_engine(sqlite, echo=True) > Base = declarative_base(bind=engine) > > class A(Base): > __tablename__ = 'a' > id = Column(Integer, primary_key=True) > value = Column(Float) > > if __name__ == '__main__': > x = exp(1.0) > print " x = %0.60f" % x > Base.metadata.drop_all() > Base.metadata.create_all() > session = create_session(bind=engine, autocommit=False) > a = A(id=1, value=x) > session.add(a) > session.commit() > print "a.value = %0.60f" % a.value > print "session.is_modified(a) = %s" % session.is_modified(a) # False > a.value = x > print "a.value = %0.60f" % a.value > print "session.is_modified(a) = %s" % session.is_modified(a) # True > session.commit() # UPDATE > session.close() > > Thanks, > > Seth > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+...@googlegroups.com <javascript:>. > To post to this group, send email to sqlal...@googlegroups.com<javascript:> > . > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/groups/opt_out. > > > >
-- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/groups/opt_out.