comparison roundup/volatiledb.py @ 902:b0d3d3535998

Bugger it. Here's the current shape of the new security implementation. Still to do: . call the security funcs from cgi and mailgw . change shipped templates to include correct initialisation and remove the old config vars ... that seems like a lot. The bulk of the work has been done though. Honest :)
author Richard Jones <richard@users.sourceforge.net>
date Thu, 25 Jul 2002 07:14:06 +0000
parents
children 502a5ae11cc5
comparison
equal deleted inserted replaced
901:31a62bcb9c80 902:b0d3d3535998
1 import weakref, re
2
3 from roundup import hyperdb
4 from roundup.hyperdb import String, Password, Date, Interval, Link, \
5 Multilink, DatabaseError, Boolean, Number
6
7 class VolatileClass(hyperdb.Class):
8 ''' This is a class that just sits in memory, no saving to disk.
9 It has no journal.
10 '''
11 def __init__(self, db, classname, **properties):
12 ''' Set up an in-memory store for the nodes of this class
13 '''
14 self.db = weakref.proxy(db) # use a weak ref to avoid circularity
15 self.classname = classname
16 self.properties = properties
17 self.id_counter = 1
18 self.store = {}
19 self.by_key = {}
20 self.key = ''
21 db.addclass(self)
22
23 def setkey(self, propname):
24 prop = self.getprops()[propname]
25 if not isinstance(prop, String):
26 raise TypeError, 'key properties must be String'
27 self.key = propname
28
29 def getprops(self, protected=1):
30 d = self.properties.copy()
31 if protected:
32 d['id'] = String()
33 return d
34
35 def create(self, **propvalues):
36 ''' Create a new node in the in-memory store
37 '''
38 if propvalues.has_key('id'):
39 raise KeyError, '"id" is reserved'
40 newid = str(self.id_counter)
41 self.id_counter += 1
42
43 # get the key value, validate it
44 if self.key:
45 keyvalue = propvalues[self.key]
46 try:
47 self.lookup(keyvalue)
48 except KeyError:
49 pass
50 else:
51 raise ValueError, 'node with key "%s" exists'%keyvalue
52 self.by_key[keyvalue] = newid
53
54 # validate propvalues
55 num_re = re.compile('^\d+$')
56
57 for key, value in propvalues.items():
58
59 # try to handle this property
60 try:
61 prop = self.properties[key]
62 except KeyError:
63 raise KeyError, '"%s" has no property "%s"'%(self.classname,
64 key)
65
66 if isinstance(prop, Link):
67 if type(value) != type(''):
68 raise ValueError, 'link value must be String'
69 link_class = self.properties[key].classname
70 # if it isn't a number, it's a key
71 if not num_re.match(value):
72 try:
73 value = self.db.classes[link_class].lookup(value)
74 except (TypeError, KeyError):
75 raise IndexError, 'new property "%s": %s not a %s'%(
76 key, value, link_class)
77 elif not self.db.hasnode(link_class, value):
78 raise IndexError, '%s has no node %s'%(link_class, value)
79
80 # save off the value
81 propvalues[key] = value
82
83 elif isinstance(prop, Multilink):
84 if type(value) != type([]):
85 raise TypeError, 'new property "%s" not a list of ids'%key
86
87 # clean up and validate the list of links
88 link_class = self.properties[key].classname
89 l = []
90 for entry in value:
91 if type(entry) != type(''):
92 raise ValueError, '"%s" link value (%s) must be '\
93 'String'%(key, value)
94 # if it isn't a number, it's a key
95 if not num_re.match(entry):
96 try:
97 entry = self.db.classes[link_class].lookup(entry)
98 except (TypeError, KeyError):
99 raise IndexError, 'new property "%s": %s not a %s'%(
100 key, entry, self.properties[key].classname)
101 l.append(entry)
102 value = l
103 propvalues[key] = value
104
105 # handle additions
106 for id in value:
107 if not self.db.hasnode(link_class, id):
108 raise IndexError, '%s has no node %s'%(link_class, id)
109
110 elif isinstance(prop, String):
111 if type(value) != type(''):
112 raise TypeError, 'new property "%s" not a string'%key
113
114 elif isinstance(prop, Password):
115 if not isinstance(value, password.Password):
116 raise TypeError, 'new property "%s" not a Password'%key
117
118 elif isinstance(prop, Date):
119 if value is not None and not isinstance(value, date.Date):
120 raise TypeError, 'new property "%s" not a Date'%key
121
122 elif isinstance(prop, Interval):
123 if value is not None and not isinstance(value, date.Interval):
124 raise TypeError, 'new property "%s" not an Interval'%key
125
126 # make sure there's data where there needs to be
127 for key, prop in self.properties.items():
128 if propvalues.has_key(key):
129 continue
130 if key == self.key:
131 raise ValueError, 'key property "%s" is required'%key
132 if isinstance(prop, Multilink):
133 propvalues[key] = []
134 else:
135 propvalues[key] = None
136
137 # done
138 self.store[newid] = propvalues
139
140 return newid
141
142 _marker = []
143 def get(self, nodeid, propname, default=_marker, cache=1):
144 ''' Get the node from the in-memory store
145 '''
146 if propname == 'id':
147 return nodeid
148 return self.store[nodeid][propname]
149
150 def set(self, nodeid, **propvalues):
151 ''' Set properties on the node in the in-memory store
152 '''
153 if not propvalues:
154 return
155
156 if propvalues.has_key('id'):
157 raise KeyError, '"id" is reserved'
158
159 node = self.store[nodeid]
160 num_re = re.compile('^\d+$')
161
162 for propname, value in propvalues.items():
163 # check to make sure we're not duplicating an existing key
164 if propname == self.key and node[propname] != value:
165 try:
166 self.lookup(value)
167 except KeyError:
168 pass
169 else:
170 raise ValueError, 'node with key "%s" exists'%value
171
172 # this will raise the KeyError if the property isn't valid
173 # ... we don't use getprops() here because we only care about
174 # the writeable properties.
175 prop = self.properties[propname]
176
177 # if the value's the same as the existing value, no sense in
178 # doing anything
179 if node.has_key(propname) and value == node[propname]:
180 del propvalues[propname]
181 continue
182
183 # do stuff based on the prop type
184 if isinstance(prop, Link):
185 link_class = self.properties[propname].classname
186 # if it isn't a number, it's a key
187 if type(value) != type(''):
188 raise ValueError, 'link value must be String'
189 if not num_re.match(value):
190 try:
191 value = self.db.classes[link_class].lookup(value)
192 except (TypeError, KeyError):
193 raise IndexError, 'new property "%s": %s not a %s'%(
194 propname, value, self.properties[propname].classname)
195
196 if not self.db.hasnode(link_class, value):
197 raise IndexError, '%s has no node %s'%(link_class, value)
198
199 elif isinstance(prop, Multilink):
200 if type(value) != type([]):
201 raise TypeError, 'new property "%s" not a list of'\
202 ' ids'%propname
203 link_class = self.properties[propname].classname
204 l = []
205 for entry in value:
206 # if it isn't a number, it's a key
207 if type(entry) != type(''):
208 raise ValueError, 'new property "%s" link value ' \
209 'must be a string'%propname
210 if not num_re.match(entry):
211 try:
212 entry = self.db.classes[link_class].lookup(entry)
213 except (TypeError, KeyError):
214 raise IndexError, 'new property "%s": %s not a %s'%(
215 propname, entry,
216 self.properties[propname].classname)
217 l.append(entry)
218 value = l
219 propvalues[propname] = value
220
221 elif isinstance(prop, String):
222 if value is not None and type(value) != type(''):
223 raise TypeError, 'new property "%s" not a string'%propname
224
225 elif isinstance(prop, Password):
226 if not isinstance(value, password.Password):
227 raise TypeError, 'new property "%s" not a Password'%propname
228 propvalues[propname] = value
229
230 elif value is not None and isinstance(prop, Date):
231 if not isinstance(value, date.Date):
232 raise TypeError, 'new property "%s" not a Date'% propname
233 propvalues[propname] = value
234
235 elif value is not None and isinstance(prop, Interval):
236 if not isinstance(value, date.Interval):
237 raise TypeError, 'new property "%s" not an '\
238 'Interval'%propname
239 propvalues[propname] = value
240
241 elif value is not None and isinstance(prop, Number):
242 try:
243 float(value)
244 except ValueError:
245 raise TypeError, 'new property "%s" not numeric'%propname
246
247 elif value is not None and isinstance(prop, Boolean):
248 try:
249 int(value)
250 except ValueError:
251 raise TypeError, 'new property "%s" not boolean'%propname
252
253 node[propname] = value
254
255 # do the set
256 self.store[nodeid] = node
257
258 def lookup(self, keyvalue):
259 ''' look up the key node in the store
260 '''
261 return self.by_key[keyvalue]
262
263 def hasnode(self, nodeid):
264 nodeid = str(nodeid)
265 return self.store.has_key(nodeid)
266
267 def list(self):
268 l = self.store.keys()
269 l.sort()
270 return l
271
272 def index(self, nodeid):
273 pass
274

Roundup Issue Tracker: http://roundup-tracker.org/