From a55934f948999e896e545c93e568b03756866c5f Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Fri, 12 Dec 2008 23:36:29 -0800 Subject: [PATCH] Fixed a Luminotes Desktop bug in which creating and then clicking on a new note link sometimes caused a red error message. This was due to a floating point rounding error in Luminotes that occured when loading note revisions from a SQLite database. --- NEWS | 2 ++ controller/Database.py | 8 ++++++- controller/test/Test_database.py | 36 +++++++++++++++++++++++++++++++- model/Note.py | 2 -- 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index c593e68..7b0193a 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ * Decreased the default note text font size, so now you can see more of your note text at once. * Added more rounded corners to several display elements. + * Fixed a Luminotes Desktop bug in which creating and then clicking on a new + note link sometimes caused a red error message. 1.5.10: December 4, 2008 * Fixed a bug in which certain new installations of Luminotes Desktop diff --git a/controller/Database.py b/controller/Database.py index b197ec8..1519903 100644 --- a/controller/Database.py +++ b/controller/Database.py @@ -69,11 +69,17 @@ class Database( object ): from pytz import utc TIMESTAMP_PATTERN = re.compile( "^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d).(\d+)(?:\+\d\d:\d\d$)?" ) + MICROSECONDS_PER_SECOND = 1000000 def convert_timestamp( value ): ( year, month, day, hours, minutes, seconds, fractional_seconds ) = \ TIMESTAMP_PATTERN.search( value ).groups( 0 ) - microseconds = int( float ( "0." + fractional_seconds ) * 1000000 ) + + # convert fractional seconds (with an arbitrary number of decimal places) to microseconds + microseconds = int( fractional_seconds ) + while microseconds > MICROSECONDS_PER_SECOND: + fractional_seconds = fractional_seconds[ : -1 ] + microseconds = int( fractional_seconds or 0 ) # ignore time zone in timestamp and assume UTC return datetime( diff --git a/controller/test/Test_database.py b/controller/test/Test_database.py index dac977f..ac51bee 100644 --- a/controller/test/Test_database.py +++ b/controller/test/Test_database.py @@ -66,6 +66,40 @@ class Test_database( object ): assert obj.revision.replace( tzinfo = utc ) == original_revision assert obj.value == basic_obj.value + def test_select_datetime( self ): + # this revision (with .504099) happens to test for a bug caused by floating point rounding errors + original_revision = "2008-01-01 01:00:42.504099+00:00" + basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 ) + + self.database.save( basic_obj ) + obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) ) + + assert obj.object_id == basic_obj.object_id + assert str( obj.revision.replace( tzinfo = utc ) ) == original_revision + assert obj.value == basic_obj.value + + def test_select_datetime_with_many_fractional_digits( self ): + original_revision = "2008-01-01 01:00:42.5032429489284+00:00" + basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 ) + + self.database.save( basic_obj ) + obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) ) + + assert obj.object_id == basic_obj.object_id + assert str( obj.revision.replace( tzinfo = utc ) ) == "2008-01-01 01:00:42.503242+00:00" + assert obj.value == basic_obj.value + + def test_select_datetime_with_zero_fractional_seconds( self ): + original_revision = "2008-01-01 01:00:42.0+00:00" + basic_obj = Stub_object( object_id = "5", revision = original_revision, value = 1 ) + + self.database.save( basic_obj ) + obj = self.database.select_one( Stub_object, Stub_object.sql_load( basic_obj.object_id ) ) + + assert obj.object_id == basic_obj.object_id + assert str( obj.revision.replace( tzinfo = utc ) ) == "2008-01-01 01:00:42+00:00" + assert obj.value == basic_obj.value + def test_select_one_tuple( self ): obj = self.database.select_one( tuple, Stub_object.sql_tuple() ) @@ -185,7 +219,7 @@ class Test_database( object ): self.connection.rollback() assert self.database.load( Stub_object, next_id ) == None - def test_next_id_with_explit_commit( self ): + def test_next_id_with_explicit_commit( self ): next_id = self.database.next_id( Stub_object, commit = False ) self.database.commit() assert next_id diff --git a/model/Note.py b/model/Note.py index 28a4847..73f32e4 100644 --- a/model/Note.py +++ b/model/Note.py @@ -136,10 +136,8 @@ class Note( Persistent ): @staticmethod def sql_load( object_id, revision = None ): if revision: - print "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note where id = %s and revision = %s;" % ( quote( object_id ), quote( revision ) ) return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note where id = %s and revision = %s;" % ( quote( object_id ), quote( revision ) ) - print "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where id = %s;" % quote( object_id ) return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where id = %s;" % quote( object_id ) @staticmethod