Skip to content

Commit c381819

Browse files
author
Richard Jones
committed
Metakit now passes all unit tests! w00t! (except the Number/Boolean unset)
- fixed bug in metakit unlink journalling - metakit now handles "unset" for most types (not Number and Boolean) - fixed bug in metakit search-by-ID
1 parent d81b1e3 commit c381819

File tree

2 files changed

+88
-16
lines changed

2 files changed

+88
-16
lines changed

roundup/backends/back_metakit.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
'''
2+
Metakit backend for Roundup, originally by Gordon McMillan.
3+
4+
Notes by Richard:
5+
6+
This backend has some behaviour specific to metakit:
7+
8+
- there's no concept of an explicit "unset" in metakit, so all types
9+
have some "unset" value:
10+
11+
========= ===== ====================================================
12+
Type Value Action when fetching from mk
13+
========= ===== ====================================================
14+
Strings '' convert to None
15+
Date 0 (seconds since 1970-01-01.00:00:00) convert to None
16+
Interval '' convert to None
17+
Number 0 ambiguious :( - do nothing
18+
Boolean 0 ambiguious :( - do nothing
19+
Link '' convert to None
20+
Multilink [] actually, mk can handle this one ;)
21+
Passowrd '' convert to None
22+
========= ===== ====================================================
23+
24+
The get/set routines handle these values accordingly by converting
25+
to/from None where they can. The Number/Boolean types are not able
26+
to handle an "unset" at all, so they default the "unset" to 0.
27+
28+
- probably a bunch of stuff that I'm not aware of yet because I haven't
29+
fully read through the source. One of these days....
30+
'''
131
from roundup import hyperdb, date, password, roundupdb, security
232
import metakit
333
from sessions import Sessions
@@ -422,7 +452,7 @@ def set(self, nodeid, **propvalues):
422452
if self.do_journal and prop.do_journal:
423453
# register the unlink with the old linked node
424454
if oldvalue:
425-
self.db.addjournal(link_class, value, _UNLINK,
455+
self.db.addjournal(link_class, oldvalue, _UNLINK,
426456
(self.classname, str(row.id), key))
427457

428458
# register the link with the newly linked node
@@ -869,7 +899,7 @@ def ff(row, crit=orcriteria):
869899
if regexes:
870900
def ff(row, r=regexes):
871901
for propname, regex in r.items():
872-
val = getattr(row, propname)
902+
val = str(getattr(row, propname))
873903
if not regex.search(val):
874904
return 0
875905
return 1
@@ -1109,25 +1139,45 @@ def _fetchML(sv):
11091139
return l
11101140

11111141
def _fetchPW(s):
1142+
''' Convert to a password.Password unless the password is '' which is
1143+
our sentinel for "unset".
1144+
'''
1145+
if s == '':
1146+
return None
11121147
p = password.Password()
11131148
p.unpack(s)
11141149
return p
11151150

11161151
def _fetchLink(n):
1152+
''' Return None if the string is empty ?otherwise ensure it's a string?
1153+
'''
11171154
return n and str(n) or None
11181155

11191156
def _fetchDate(n):
1157+
''' Convert the timestamp to a date.Date instance - unless it's 0 which
1158+
is our sentinel for "unset".
1159+
'''
1160+
if n == 0:
1161+
return None
11201162
return date.Date(time.gmtime(n))
11211163

1164+
def _fetchInterval(n):
1165+
''' Convert to a date.Interval unless the interval is '' which is our
1166+
sentinel for "unset".
1167+
'''
1168+
if n == '':
1169+
return None
1170+
return date.Interval(n)
1171+
11221172
_converters = {
11231173
hyperdb.Date : _fetchDate,
11241174
hyperdb.Link : _fetchLink,
11251175
hyperdb.Multilink : _fetchML,
1126-
hyperdb.Interval : date.Interval,
1176+
hyperdb.Interval : _fetchInterval,
11271177
hyperdb.Password : _fetchPW,
11281178
hyperdb.Boolean : lambda n: n,
11291179
hyperdb.Number : lambda n: n,
1130-
hyperdb.String : str,
1180+
hyperdb.String : lambda s: s and str(s) or None,
11311181
}
11321182

11331183
class FileName(hyperdb.String):

test/test_db.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: test_db.py,v 1.67 2003-01-14 10:52:05 richard Exp $
18+
# $Id: test_db.py,v 1.68 2003-01-20 23:03:41 richard Exp $
1919

2020
import unittest, os, shutil, time
2121

@@ -185,17 +185,23 @@ def testBooleanChange(self):
185185
self.assertEqual(1, self.db.user.get(userid, 'assignable'))
186186
self.db.user.set(userid, assignable=0)
187187
self.assertEqual(self.db.user.get(userid, 'assignable'), 0)
188-
self.db.user.set(userid, assignable=None)
189-
self.assertEqual(self.db.user.get('1', "assignable"), None)
188+
189+
def testBooleanUnset(self):
190+
nid = self.db.user.create(username='foo', assignable=1)
191+
self.db.user.set(nid, assignable=None)
192+
self.assertEqual(self.db.user.get(nid, "assignable"), None)
190193

191194
def testNumberChange(self):
192195
nid = self.db.user.create(username='foo', age=1)
193196
self.assertEqual(1, self.db.user.get(nid, 'age'))
194-
self.db.user.set('1', age=3)
195-
self.assertNotEqual(self.db.user.get('1', 'age'), 1)
196-
self.db.user.set('1', age=1.0)
197-
self.db.user.set('1', age=None)
198-
self.assertEqual(self.db.user.get('1', "age"), None)
197+
self.db.user.set(nid, age=3)
198+
self.assertNotEqual(self.db.user.get(nid, 'age'), 1)
199+
self.db.user.set(nid, age=1.0)
200+
201+
def testNumberUnset(self):
202+
nid = self.db.user.create(username='foo', age=1)
203+
self.db.user.set(nid, age=None)
204+
self.assertEqual(self.db.user.get(nid, "age"), None)
199205

200206
def testKeyValue(self):
201207
newid = self.db.user.create(username="spam")
@@ -386,15 +392,19 @@ def testExceptions(self):
386392
# invalid multilink index
387393
ar(IndexError, self.db.issue.set, id, title='foo', status='1',
388394
nosy=['10'])
395+
# NOTE: the following increment the username to avoid problems
396+
# within metakit's backend (it creates the node, and then sets the
397+
# info, so the create (and by a fluke the username set) go through
398+
# before the age/assignable/etc. set, which raises the exception)
389399
# invalid number value
390400
ar(TypeError, self.db.user.create, username='foo', age='a')
391401
# invalid boolean value
392-
ar(TypeError, self.db.user.create, username='foo', assignable='true')
393-
nid = self.db.user.create(username='foo')
402+
ar(TypeError, self.db.user.create, username='foo2', assignable='true')
403+
nid = self.db.user.create(username='foo3')
394404
# invalid number value
395-
ar(TypeError, self.db.user.set, nid, username='foo', age='a')
405+
ar(TypeError, self.db.user.set, nid, age='a')
396406
# invalid boolean value
397-
ar(TypeError, self.db.user.set, nid, username='foo', assignable='true')
407+
ar(TypeError, self.db.user.set, nid, assignable='true')
398408

399409
def testJournals(self):
400410
self.db.user.create(username="mary")
@@ -808,6 +818,18 @@ def testTransactions(self):
808818
self.assertEqual(num_files2, len(self.db.file.list()))
809819
self.assertEqual(num_rfiles2, num_rfiles-1)
810820

821+
def testBooleanUnset(self):
822+
# XXX: metakit can't unset Booleans :(
823+
nid = self.db.user.create(username='foo', assignable=1)
824+
self.db.user.set(nid, assignable=None)
825+
self.assertEqual(self.db.user.get(nid, "assignable"), 0)
826+
827+
def testNumberUnset(self):
828+
# XXX: metakit can't unset Numbers :(
829+
nid = self.db.user.create(username='foo', age=1)
830+
self.db.user.set(nid, age=None)
831+
self.assertEqual(self.db.user.get(nid, "age"), 0)
832+
811833
class metakitReadOnlyDBTestCase(anydbmReadOnlyDBTestCase):
812834
def setUp(self):
813835
from roundup.backends import metakit

0 commit comments

Comments
 (0)