Mercurial > p > roundup > code
comparison roundup/hyperdb.py @ 475:a1a44636bace
Fix breakage caused by transaction changes.
Sorry for the huge checkin message - I was only intending to implement
[SF#496356] but I found a number of places where things had been
broken by transactions:
. modified ROUNDUPDBSENDMAILDEBUG to be SENDMAILDEBUG and hold a filename
for _all_ roundup-generated smtp messages to be sent to.
. the transaction cache had broken the roundupdb.Class set() reactors
. newly-created author users in the mailgw weren't being committed to the db
Stuff that made it into CHANGES.txt (ie. the stuff I was actually working
on when I found that stuff :):
. [SF#496356] Use threading in messages
. detectors were being registered multiple times
. added tests for mailgw
. much better attaching of erroneous messages in the mail gateway
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Wed, 02 Jan 2002 02:31:38 +0000 |
| parents | a3548136f7bb |
| children | 05a46da7293a |
comparison
equal
deleted
inserted
replaced
| 474:ef06a66a0b72 | 475:a1a44636bace |
|---|---|
| 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" | 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" |
| 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, | 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
| 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. | 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| 17 # | 17 # |
| 18 # $Id: hyperdb.py,v 1.43 2001-12-20 06:13:24 rochecompaan Exp $ | 18 # $Id: hyperdb.py,v 1.44 2002-01-02 02:31:38 richard Exp $ |
| 19 | 19 |
| 20 __doc__ = """ | 20 __doc__ = """ |
| 21 Hyperdatabase implementation, especially field types. | 21 Hyperdatabase implementation, especially field types. |
| 22 """ | 22 """ |
| 23 | 23 |
| 238 # done | 238 # done |
| 239 self.db.addnode(self.classname, newid, propvalues) | 239 self.db.addnode(self.classname, newid, propvalues) |
| 240 self.db.addjournal(self.classname, newid, 'create', propvalues) | 240 self.db.addjournal(self.classname, newid, 'create', propvalues) |
| 241 return newid | 241 return newid |
| 242 | 242 |
| 243 def get(self, nodeid, propname, default=_marker): | 243 def get(self, nodeid, propname, default=_marker, cache=1): |
| 244 """Get the value of a property on an existing node of this class. | 244 """Get the value of a property on an existing node of this class. |
| 245 | 245 |
| 246 'nodeid' must be the id of an existing node of this class or an | 246 'nodeid' must be the id of an existing node of this class or an |
| 247 IndexError is raised. 'propname' must be the name of a property | 247 IndexError is raised. 'propname' must be the name of a property |
| 248 of this class or a KeyError is raised. | 248 of this class or a KeyError is raised. |
| 249 | |
| 250 'cache' indicates whether the transaction cache should be queried | |
| 251 for the node. If the node has been modified and you need to | |
| 252 determine what its values prior to modification are, you need to | |
| 253 set cache=0. | |
| 249 """ | 254 """ |
| 250 if propname == 'id': | 255 if propname == 'id': |
| 251 return nodeid | 256 return nodeid |
| 252 | 257 |
| 253 # get the node's dict | 258 # get the node's dict |
| 254 d = self.db.getnode(self.classname, nodeid) | 259 d = self.db.getnode(self.classname, nodeid, cache=cache) |
| 255 if not d.has_key(propname) and default is not _marker: | 260 if not d.has_key(propname) and default is not _marker: |
| 256 return default | 261 return default |
| 257 | 262 |
| 258 # get the value | 263 # get the value |
| 259 prop = self.properties[propname] | 264 prop = self.properties[propname] |
| 269 return p | 274 return p |
| 270 | 275 |
| 271 return d[propname] | 276 return d[propname] |
| 272 | 277 |
| 273 # XXX not in spec | 278 # XXX not in spec |
| 274 def getnode(self, nodeid): | 279 def getnode(self, nodeid, cache=1): |
| 275 ''' Return a convenience wrapper for the node | 280 ''' Return a convenience wrapper for the node. |
| 281 | |
| 282 'nodeid' must be the id of an existing node of this class or an | |
| 283 IndexError is raised. | |
| 284 | |
| 285 'cache' indicates whether the transaction cache should be queried | |
| 286 for the node. If the node has been modified and you need to | |
| 287 determine what its values prior to modification are, you need to | |
| 288 set cache=0. | |
| 276 ''' | 289 ''' |
| 277 return Node(self, nodeid) | 290 return Node(self, nodeid, cache=cache) |
| 278 | 291 |
| 279 def set(self, nodeid, **propvalues): | 292 def set(self, nodeid, **propvalues): |
| 280 """Modify a property on an existing node of this class. | 293 """Modify a property on an existing node of this class. |
| 281 | 294 |
| 282 'nodeid' must be the id of an existing node of this class or an | 295 'nodeid' must be the id of an existing node of this class or an |
| 822 | 835 |
| 823 # XXX not in spec | 836 # XXX not in spec |
| 824 class Node: | 837 class Node: |
| 825 ''' A convenience wrapper for the given node | 838 ''' A convenience wrapper for the given node |
| 826 ''' | 839 ''' |
| 827 def __init__(self, cl, nodeid): | 840 def __init__(self, cl, nodeid, cache=1): |
| 828 self.__dict__['cl'] = cl | 841 self.__dict__['cl'] = cl |
| 829 self.__dict__['nodeid'] = nodeid | 842 self.__dict__['nodeid'] = nodeid |
| 843 self.cache = cache | |
| 830 def keys(self, protected=1): | 844 def keys(self, protected=1): |
| 831 return self.cl.getprops(protected=protected).keys() | 845 return self.cl.getprops(protected=protected).keys() |
| 832 def values(self, protected=1): | 846 def values(self, protected=1): |
| 833 l = [] | 847 l = [] |
| 834 for name in self.cl.getprops(protected=protected).keys(): | 848 for name in self.cl.getprops(protected=protected).keys(): |
| 835 l.append(self.cl.get(self.nodeid, name)) | 849 l.append(self.cl.get(self.nodeid, name, cache=self.cache)) |
| 836 return l | 850 return l |
| 837 def items(self, protected=1): | 851 def items(self, protected=1): |
| 838 l = [] | 852 l = [] |
| 839 for name in self.cl.getprops(protected=protected).keys(): | 853 for name in self.cl.getprops(protected=protected).keys(): |
| 840 l.append((name, self.cl.get(self.nodeid, name))) | 854 l.append((name, self.cl.get(self.nodeid, name, cache=self.cache))) |
| 841 return l | 855 return l |
| 842 def has_key(self, name): | 856 def has_key(self, name): |
| 843 return self.cl.getprops().has_key(name) | 857 return self.cl.getprops().has_key(name) |
| 844 def __getattr__(self, name): | 858 def __getattr__(self, name): |
| 845 if self.__dict__.has_key(name): | 859 if self.__dict__.has_key(name): |
| 846 return self.__dict__[name] | 860 return self.__dict__[name] |
| 847 try: | 861 try: |
| 848 return self.cl.get(self.nodeid, name) | 862 return self.cl.get(self.nodeid, name, cache=self.cache) |
| 849 except KeyError, value: | 863 except KeyError, value: |
| 850 # we trap this but re-raise it as AttributeError - all other | 864 # we trap this but re-raise it as AttributeError - all other |
| 851 # exceptions should pass through untrapped | 865 # exceptions should pass through untrapped |
| 852 pass | 866 pass |
| 853 # nope, no such attribute | 867 # nope, no such attribute |
| 854 raise AttributeError, str(value) | 868 raise AttributeError, str(value) |
| 855 def __getitem__(self, name): | 869 def __getitem__(self, name): |
| 856 return self.cl.get(self.nodeid, name) | 870 return self.cl.get(self.nodeid, name, cache=self.cache) |
| 857 def __setattr__(self, name, value): | 871 def __setattr__(self, name, value): |
| 858 try: | 872 try: |
| 859 return self.cl.set(self.nodeid, **{name: value}) | 873 return self.cl.set(self.nodeid, **{name: value}) |
| 860 except KeyError, value: | 874 except KeyError, value: |
| 861 raise AttributeError, str(value) | 875 raise AttributeError, str(value) |
| 873 cl.create(name=option[i], order=i) | 887 cl.create(name=option[i], order=i) |
| 874 return hyperdb.Link(name) | 888 return hyperdb.Link(name) |
| 875 | 889 |
| 876 # | 890 # |
| 877 # $Log: not supported by cvs2svn $ | 891 # $Log: not supported by cvs2svn $ |
| 892 # Revision 1.43 2001/12/20 06:13:24 rochecompaan | |
| 893 # Bugs fixed: | |
| 894 # . Exception handling in hyperdb for strings-that-look-like numbers got | |
| 895 # lost somewhere | |
| 896 # . Internet Explorer submits full path for filename - we now strip away | |
| 897 # the path | |
| 898 # Features added: | |
| 899 # . Link and multilink properties are now displayed sorted in the cgi | |
| 900 # interface | |
| 901 # | |
| 878 # Revision 1.42 2001/12/16 10:53:37 richard | 902 # Revision 1.42 2001/12/16 10:53:37 richard |
| 879 # take a copy of the node dict so that the subsequent set | 903 # take a copy of the node dict so that the subsequent set |
| 880 # operation doesn't modify the oldvalues structure | 904 # operation doesn't modify the oldvalues structure |
| 881 # | 905 # |
| 882 # Revision 1.41 2001/12/15 23:47:47 richard | 906 # Revision 1.41 2001/12/15 23:47:47 richard |
