Skip to content

Commit 8f7cbd3

Browse files
committed
Implement double-precision Number
.. as an option to the 'Number' property.
1 parent f81a9ac commit 8f7cbd3

File tree

6 files changed

+79
-19
lines changed

6 files changed

+79
-19
lines changed

CHANGES.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ Features:
145145
- When storing user-defined queries we now store the template with the
146146
query if the template name is different from 'index'. This allows
147147
stored queries for templates different from the default 'index'
148-
template.
148+
template. (Ralf Schlatterbeck)
149+
- Number properties now have an optional attribute use_double to request
150+
double precision float as the storage type for this property. (Ralf
151+
Schlatterbeck)
149152

150153
Fixed:
151154

@@ -329,15 +332,16 @@ Fixed:
329332
exceptions. This occured for example if editing an issue with the
330333
classic template and setting 'superseder' to a non-existing issue
331334
number. All changes to the form where the original field was non-empty
332-
were lost.
335+
were lost. (Ralf Schlatterbeck)
333336
- Fix submit_once Javascript function: This needs to return a boolean
334337
value (not and integer like 0 or 1). And the work-around for an
335338
ancient version of Internet Explorer would make it break for a recent
336339
Firefox. The old version would show the popup but after clicking away
337340
the alert it would load the page. The new version (tested with
338-
Chromium and Firefox) doesn't load the page.
341+
Chromium and Firefox) doesn't load the page. (Ralf Schlatterbeck)
339342
- Fix Traceback in backends/portalocker.py on windows due to missing
340343
windll import, thanks to Heiko Stegmann for suggesting a first fix.
344+
(Ralf Schlatterbeck)
341345

342346

343347
2016-01-11: 1.5.1

doc/customizing.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,8 @@ A Class is comprised of one or more properties of the following types:
656656
* Date properties store date-and-time stamps. Their values are Timestamp
657657
objects.
658658
* Integer properties store integer values. (Number can store real/float values.)
659-
* Number properties store numeric values.
659+
* Number properties store numeric values. There is an option to use
660+
double-precision floating point numbers.
660661
* Boolean properties store on/off, yes/no, true/false values.
661662
* A Link property refers to a single other item selected from a
662663
specified class. The class is part of the property; the value is an
@@ -671,6 +672,8 @@ behaviour:
671672
property should be part of the full text index. The default is 'no' but this
672673
can be set to 'yes' to allow a property's contents to be in the full
673674
text index.
675+
* Number properties can have a ``use_double`` attribute that, when set
676+
to ``True``, will use double precision floating point in the database.
674677
* Link and Multilink properties can have several attributes:
675678

676679
- ``do_journal``: By default, every change of a link property is

roundup/backends/back_sqlite.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ class Database(rdbms_common.Database):
5454
# used by some code to switch styles of query
5555
implements_intersect = 1
5656

57+
# used in generic backend to determine if db supports
58+
# 'DOUBLE PRECISION' for floating point numbers. Note that sqlite
59+
# already has double precision as its standard 'REAL' type. So this
60+
# is set to False here.
61+
62+
implements_double_precision = False
63+
5764
hyperdb_to_sql_datatypes = {
5865
hyperdb.String : 'VARCHAR(255)',
5966
hyperdb.Date : 'VARCHAR(30)',

roundup/backends/rdbms_common.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,10 @@ def reindex(self, classname=None, show_progress=False):
453453
klass.index(nodeid)
454454
self.indexer.save_index()
455455

456+
# Used here in the generic backend to determine if the database
457+
# supports 'DOUBLE PRECISION' for floating point numbers.
458+
implements_double_precision = True
459+
456460
hyperdb_to_sql_datatypes = {
457461
hyperdb.String : 'TEXT',
458462
hyperdb.Date : 'TIMESTAMP',
@@ -464,9 +468,12 @@ def reindex(self, classname=None, show_progress=False):
464468
hyperdb.Integer : 'INTEGER',
465469
}
466470

467-
def hyperdb_to_sql_datatype(self, propclass):
471+
def hyperdb_to_sql_datatype(self, propclass, prop = None):
468472

469473
datatype = self.hyperdb_to_sql_datatypes.get(propclass)
474+
if self.implements_double_precision and prop and \
475+
isinstance(prop, Number) and prop.use_double:
476+
datatype = 'DOUBLE PRECISION'
470477
if datatype:
471478
return datatype
472479

@@ -500,7 +507,7 @@ def determine_columns(self, properties):
500507
#and prop.find('Multilink') != -1:
501508
#mls.append(col)
502509

503-
datatype = self.hyperdb_to_sql_datatype(prop.__class__)
510+
datatype = self.hyperdb_to_sql_datatype(prop.__class__, prop)
504511
cols.append(('_'+col, datatype))
505512

506513
# Intervals stored as two columns
@@ -579,7 +586,7 @@ def update_class(self, spec, old_spec, force=0):
579586
self.create_multilink_table(spec, propname)
580587
else:
581588
# add the column
582-
coltype = self.hyperdb_to_sql_datatype(prop.__class__)
589+
coltype = self.hyperdb_to_sql_datatype(prop.__class__, prop)
583590
sql = 'alter table _%s add column _%s %s'%(
584591
spec.classname, propname, coltype)
585592
self.sql(sql)

roundup/hyperdb.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,17 @@ def from_raw(self, value, **kw):
293293

294294
class Number(_Type):
295295
"""An object designating a numeric property"""
296+
def __init__(self, use_double = False, **kw):
297+
""" The value use_double tells the database backend to use a
298+
floating-point format with more precision than the default.
299+
Usually implemented by type 'double precision' in the sql
300+
backend. The default is to use single-precision float (aka
301+
'real') in the db. Note that sqlite already uses 8-byte for
302+
floating point numbers.
303+
"""
304+
self.use_double = use_double
305+
_Type.__init__ (self, **kw)
306+
super(Number, self).__init__(**kw)
296307
def from_raw(self, value, **kw):
297308
value = value.strip()
298309
try:

test/db_test_base.py

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@ def setupSchema(db, create, module):
8080
status.setkey("name")
8181
priority = module.Class(db, "priority", name=String(), order=String())
8282
priority.setkey("name")
83-
user = module.Class(db, "user", username=String(), password=Password(quiet=True),
84-
assignable=Boolean(quiet=True), age=Number(quiet=True), roles=String(), address=String(),
85-
rating=Integer(quiet=True), supervisor=Link('user'),realname=String(quiet=True))
83+
user = module.Class(db, "user", username=String(),
84+
password=Password(quiet=True), assignable=Boolean(quiet=True),
85+
age=Number(quiet=True), roles=String(), address=String(),
86+
rating=Integer(quiet=True), supervisor=Link('user'),
87+
realname=String(quiet=True), longnumber=Number(use_double=True))
8688
user.setkey("username")
8789
file = module.FileClass(db, "file", name=String(), type=String(),
8890
comment=String(indexme="yes"), fooz=Password())
@@ -92,18 +94,16 @@ def setupSchema(db, create, module):
9294
mynosy = Multilink("user")
9395
mynosy.quiet = True
9496
issue = module.IssueClass(db, "issue", title=String(indexme="yes"),
95-
status=Link("status"), nosy=mynosy, deadline=Date(quiet=True),
96-
foo=Interval(quiet=True, default_value=date.Interval('-1w')), files=Multilink("file"), assignedto=Link('user', quiet=True),
97-
priority=Link('priority'), spam=Multilink('msg'),
98-
feedback=Link('msg'))
97+
status=Link("status"), nosy=mynosy, deadline=Date(quiet=True),
98+
foo=Interval(quiet=True, default_value=date.Interval('-1w')),
99+
files=Multilink("file"), assignedto=Link('user', quiet=True),
100+
priority=Link('priority'), spam=Multilink('msg'), feedback=Link('msg'))
99101
stuff = module.Class(db, "stuff", stuff=String())
100102
session = module.Class(db, 'session', title=String())
101103
msg = module.FileClass(db, "msg", date=Date(),
102-
author=Link("user", do_journal='no'),
103-
files=Multilink('file'), inreplyto=String(),
104-
messageid=String(),
105-
recipients=Multilink("user", do_journal='no')
106-
)
104+
author=Link("user", do_journal='no'), files=Multilink('file'),
105+
inreplyto=String(), messageid=String(),
106+
recipients=Multilink("user", do_journal='no'))
107107
session.disableJournalling()
108108
db.post_init()
109109
if create:
@@ -538,6 +538,34 @@ def testNumberUnset(self):
538538
self.db.user.set(nid, age=None)
539539
self.assertEqual(self.db.user.get(nid, "age"), None)
540540

541+
# Long number
542+
def testDoubleChange(self):
543+
lnl = 100.12345678
544+
ln = 100.123456789
545+
lng = 100.12345679
546+
nid = self.db.user.create(username='foo', longnumber=ln)
547+
self.assertEqual(self.db.user.get(nid, 'longnumber') < lng, True)
548+
self.assertEqual(self.db.user.get(nid, 'longnumber') > lnl, True)
549+
lnl = 1.0012345678e55
550+
ln = 1.00123456789e55
551+
lng = 1.0012345679e55
552+
self.db.user.set(nid, longnumber=ln)
553+
self.assertEqual(self.db.user.get(nid, 'longnumber') < lng, True)
554+
self.assertEqual(self.db.user.get(nid, 'longnumber') > lnl, True)
555+
self.db.user.set(nid, longnumber=-1)
556+
self.assertEqual(self.db.user.get(nid, 'longnumber'), -1)
557+
self.db.user.set(nid, longnumber=0)
558+
self.assertEqual(self.db.user.get(nid, 'longnumber'), 0)
559+
560+
nid = self.db.user.create(username='bar', longnumber=0)
561+
self.assertEqual(self.db.user.get(nid, 'longnumber'), 0)
562+
563+
def testDoubleUnset(self):
564+
nid = self.db.user.create(username='foo', longnumber=1.2345)
565+
self.db.user.set(nid, longnumber=None)
566+
self.assertEqual(self.db.user.get(nid, "longnumber"), None)
567+
568+
541569
# Integer
542570
def testIntegerChange(self):
543571
nid = self.db.user.create(username='foo', rating=100)

0 commit comments

Comments
 (0)