summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 750dff3)
raw | patch | inline | side by side (parent: 750dff3)
author | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 4 Sep 2003 00:47:01 +0000 (00:47 +0000) | ||
committer | richard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Thu, 4 Sep 2003 00:47:01 +0000 (00:47 +0000) |
Cleaned up caching API / comments in backends.
Fixes to docs.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1847 57a73879-2fb5-44c3-a270-3262357dd7e2
Fixes to docs.
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1847 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index 2e227b442db5b384ed8b639431b6ebbf6391f394..48fe0142254934333426f730c3f441fe27bfd6f2 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
This file contains the changes to the Roundup system over time. The entries
are given with the most recent entry first.
-2003-08-?? 0.6.1
+2003-09-?? 0.6.2
+Fixed:
+- cleaned up, clarified internal caching API in *dbm backends
+
+
+2003-08-31 0.6.1
Fixed:
- Add note about installing cgi-bin with a different interpreter
- Importing wasn't setting None values explicitly when it should have been
diff --git a/doc/announcement.txt b/doc/announcement.txt
index 51dc01252157ed590418fa765a40ac1308e94958..3a53e0356a00f7dc1543702a8a947996d3348154 100644 (file)
--- a/doc/announcement.txt
+++ b/doc/announcement.txt
=================================================
-SC-Track Roundup 0.6.0 - an issue tracking system
+SC-Track Roundup 0.6.1 - an issue tracking system
=================================================
-I'm pleased to announce the latest feature-packed release of Roundup. See
-below for a list of some of the goodies included in this release.
+I'm pleased to announce this maintenance release of Roundup. This fix
+introduces Python2.3 compatibility. My thanks to Paul Dubois for
+contributing the csv module compatibility layer.
If you're upgrading from an older version of Roundup you *must* follow
the "Software Upgrade" guidelines given in the maintenance documentation.
Unfortunately, the Zope frontend for Roundup is currently broken. I hope to
-revive it in a future 0.6 bugfix release.
-
-The gadfly backend has now been removed, having served its purpose as a
-template for other RDBMS implementations. It is replaced by the sqlite and
-mysql backends.
+revive it in a future 0.6 maintenance release.
Roundup requires python 2.1.3 or later for correct operation.
-The 0.6 release has lots of new goodies including:
-
-- new instant-gratification Demo Mode ("python demo.py" :)
-- added mysql backend (see doc/mysql.txt for details)
-- web interface cleanups including nicer history display, nicer index
- navigation and nicer popup list windows
-- searching of date ranges
-- better international support, including utf-8 email handling and ability
- to display localized dates in web interface.
-- more documentation including revamped design document, unix manual pages
- and some FAQ entries
-- significantly more powerful form handling allowing editing of multiple
- items and creation of multiple items
-- tracker templates can contain subdirectories and static files (e.g.
- images) and we may now distribute templates separately from Roundup.
- Template HTML files now have a .html extension too.
-- user registration is now a two-step process, with confirmation from the
- email address supplied in the registration form, and we also have a
- password reset feature for forgotten password / login
-- Windows Service mode for roundup-server when daemonification is
- attempted on Windows
-- lots of speed enhancements, making the web interface much more responsive
-- fixed issues with dumb email or web clients
-- email system handles more SMTP and POP features (TLS, APOP, ...)
-- lots more little tweaks and back-end work...
+This release fixes some bugs:
+
+- Add note about installing cgi-bin with a different interpreter
+- Importing wasn't setting None values explicitly when it should have been
+- Fixed import warning regarding 0xffff0000 literal, finally, really this
+ time. Checked on win2k. (sf bug 786711)
+- Fix CGI editCSV action to handle metakit's integer itemids
+- Apply fix for "remove" links from Klamer Schutte
+- Added permission check on "remove" link while I was there..
+- Applied CSV fix for python2.3 (sf bug 790363)
+- Fixed form padding in LHS menu (sf bug 790502)
+- Fixed upgrading docs for timezones (sf bug 790498)
+- Set the content type on page templates (can have XML templates now)
+- Various cosmetic fixes (thanks James Kew for being persistent :)
+- Applied patch 739314 (sorry John!)
+
+To give Roundup a try, just download (see below), unpack and run::
+
+ python demo.py
Source and documentation is available at the website:
http://roundup.sourceforge.net/
diff --git a/doc/customizing.txt b/doc/customizing.txt
index 5df11ba0bd32b08a1591cc11bfa4f35a83a2c562..9ac41f505f589a9a5e5db1fe510357bba2a84180 100644 (file)
--- a/doc/customizing.txt
+++ b/doc/customizing.txt
Customising Roundup
===================
-:Version: $Revision: 1.95 $
+:Version: $Revision: 1.96 $
.. This document borrows from the ZopeBook section on ZPT. The original is at:
http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx
There are several methods available on these wrapper objects:
=========== ================================================================
-Method Description
+Method Description
=========== ================================================================
plain render a "plain" representation of the property. This method
may take two arguments:
index e0f516ce1e5b5c5124d5d31c72f8a85a5e66ac32..b0a8556ea238791eae731d60a603268f4e238896 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.123 2003-08-26 00:06:55 richard Exp $
+#$Id: back_anydbm.py,v 1.124 2003-09-04 00:47:01 richard Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
def getnode(self, classname, nodeid, db=None, cache=1):
''' get a node from the database
+
+ Note the "cache" parameter is not used, and exists purely for
+ backward compatibility!
'''
if __debug__:
print >>hyperdb.DEBUG, 'getnode', (self, classname, nodeid, db)
- if cache:
- # try the cache
- cache_dict = self.cache.setdefault(classname, {})
- if cache_dict.has_key(nodeid):
- if __debug__:
- print >>hyperdb.TRACE, 'get %s %s cached'%(classname,
- nodeid)
- return cache_dict[nodeid]
+
+ # try the cache
+ cache_dict = self.cache.setdefault(classname, {})
+ if cache_dict.has_key(nodeid):
+ if __debug__:
+ print >>hyperdb.TRACE, 'get %s %s cached'%(classname,
+ nodeid)
+ return cache_dict[nodeid]
if __debug__:
print >>hyperdb.TRACE, 'get %s %s'%(classname, nodeid)
IndexError is raised. 'propname' must be the name of a property
of this class or a KeyError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backward compatibility, and is not used.
Attempts to get the "creation" or "activity" properties should
do the right thing.
return nodeid
# get the node's dict
- d = self.db.getnode(self.classname, nodeid, cache=cache)
+ d = self.db.getnode(self.classname, nodeid)
# check for one of the special props
if propname == 'creation':
'nodeid' must be the id of an existing node of this class or an
IndexError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
'''
- return Node(self, nodeid, cache=cache)
+ return Node(self, nodeid)
def set(self, nodeid, **propvalues):
'''Modify a property on an existing node of this class.
self.fireAuditors('set', nodeid, propvalues)
# Take a copy of the node dict so that the subsequent set
# operation doesn't modify the oldvalues structure.
- try:
- # try not using the cache initially
- oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid,
- cache=0))
- except IndexError:
- # this will be needed if somone does a create() and set()
- # with no intervening commit()
- oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid))
+ oldvalues = copy.deepcopy(self.db.getnode(self.classname, nodeid))
node = self.db.getnode(self.classname, nodeid)
if node.has_key(self.db.RETIRED_FLAG):
return newid
def get(self, nodeid, propname, default=_marker, cache=1):
- ''' trap the content propname and get it from the file
+ ''' Trap the content propname and get it from the file
+
+ 'cache' exists for backwards compatibility, and is not used.
'''
poss_msg = 'Possibly an access right configuration problem.'
if propname == 'content':
return 'ERROR reading file: %s%s\n%s\n%s'%(
self.classname, nodeid, poss_msg, strerror)
if default is not _marker:
- return Class.get(self, nodeid, propname, default, cache=cache)
+ return Class.get(self, nodeid, propname, default)
else:
- return Class.get(self, nodeid, propname, cache=cache)
+ return Class.get(self, nodeid, propname)
def getprops(self, protected=1):
''' In addition to the actual properties on the node, these methods
index 60997dff9aafd678766dcf672c5634263eda1227..64ab3d7841b433dba49a80a2460c352acb2bd252 100755 (executable)
-# $Id: back_metakit.py,v 1.48 2003-08-26 00:06:56 richard Exp $
+# $Id: back_metakit.py,v 1.49 2003-09-04 00:47:01 richard Exp $
'''
Metakit backend for Roundup, originally by Gordon McMillan.
return str(newid)
def get(self, nodeid, propname, default=_marker, cache=1):
- # default and cache aren't in the spec
- # cache=0 means "original value"
+ '''
+ 'cache' exists for backwards compatibility, and is not used.
+ '''
view = self.getview()
id = int(nodeid)
Class.__init__(self, db, classname, **properties)
def get(self, nodeid, propname, default=_marker, cache=1):
- x = Class.get(self, nodeid, propname, default, cache)
+ x = Class.get(self, nodeid, propname, default)
poss_msg = 'Possibly an access right configuration problem.'
if propname == 'content':
if x.startswith('file:'):
index 2bbe0e00479fd4bb5ac165fc178fe8e7446edf89..1bdec79c8153a4dc70929a75d420bc7ddd5040b5 100644 (file)
-# $Id: rdbms_common.py,v 1.59 2003-08-26 00:06:56 richard Exp $
+# $Id: rdbms_common.py,v 1.60 2003-09-04 00:47:01 richard Exp $
''' Relational database (SQL) backend common code.
Basics:
IndexError is raised. 'propname' must be the name of a property
of this class or a KeyError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
'''
if propname == 'id':
return nodeid
'nodeid' must be the id of an existing node of this class or an
IndexError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
'''
- return Node(self, nodeid, cache=cache)
+ return Node(self, nodeid)
def set(self, nodeid, **propvalues):
'''Modify a property on an existing node of this class.
_marker = []
def get(self, nodeid, propname, default=_marker, cache=1):
- ''' trap the content propname and get it from the file
+ ''' Trap the content propname and get it from the file
+
+ 'cache' exists for backwards compatibility, and is not used.
'''
poss_msg = 'Possibly a access right configuration problem.'
if propname == 'content':
return 'ERROR reading file: %s%s\n%s\n%s'%(
self.classname, nodeid, poss_msg, strerror)
if default is not self._marker:
- return Class.get(self, nodeid, propname, default, cache=cache)
+ return Class.get(self, nodeid, propname, default)
else:
- return Class.get(self, nodeid, propname, cache=cache)
+ return Class.get(self, nodeid, propname)
def getprops(self, protected=1):
''' In addition to the actual properties on the node, these methods
diff --git a/roundup/hyperdb.py b/roundup/hyperdb.py
index 4ab22268aafdf57cd4b7b98022dad397576246ea..78ca20e1a47fd97eb11758f9388151ca5cfd3c4a 100644 (file)
--- a/roundup/hyperdb.py
+++ b/roundup/hyperdb.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: hyperdb.py,v 1.87 2003-03-17 22:03:03 kedder Exp $
+# $Id: hyperdb.py,v 1.88 2003-09-04 00:47:01 richard Exp $
"""
Hyperdatabase implementation, especially field types.
def getnode(self, classname, nodeid, db=None, cache=1):
'''Get a node from the database.
+
+ 'cache' exists for backwards compatibility, and is not used.
'''
raise NotImplementedError
IndexError is raised. 'propname' must be the name of a property
of this class or a KeyError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
"""
raise NotImplementedError
'nodeid' must be the id of an existing node of this class or an
IndexError is raised.
- 'cache' indicates whether the transaction cache should be queried
- for the node. If the node has been modified and you need to
- determine what its values prior to modification are, you need to
- set cache=0.
+ 'cache' exists for backwards compatibility, and is not used.
'''
- return Node(self, nodeid, cache=cache)
+ return Node(self, nodeid)
def set(self, nodeid, **propvalues):
"""Modify a property on an existing node of this class.
def __init__(self, cl, nodeid, cache=1):
self.__dict__['cl'] = cl
self.__dict__['nodeid'] = nodeid
- self.__dict__['cache'] = cache
def keys(self, protected=1):
return self.cl.getprops(protected=protected).keys()
def values(self, protected=1):
l = []
for name in self.cl.getprops(protected=protected).keys():
- l.append(self.cl.get(self.nodeid, name, cache=self.cache))
+ l.append(self.cl.get(self.nodeid, name))
return l
def items(self, protected=1):
l = []
for name in self.cl.getprops(protected=protected).keys():
- l.append((name, self.cl.get(self.nodeid, name, cache=self.cache)))
+ l.append((name, self.cl.get(self.nodeid, name)))
return l
def has_key(self, name):
return self.cl.getprops().has_key(name)
if self.__dict__.has_key(name):
return self.__dict__[name]
try:
- return self.cl.get(self.nodeid, name, cache=self.cache)
+ return self.cl.get(self.nodeid, name)
except KeyError, value:
# we trap this but re-raise it as AttributeError - all other
# exceptions should pass through untrapped
# nope, no such attribute
raise AttributeError, str(value)
def __getitem__(self, name):
- return self.cl.get(self.nodeid, name, cache=self.cache)
+ return self.cl.get(self.nodeid, name)
def __setattr__(self, name, value):
try:
return self.cl.set(self.nodeid, **{name: value})
diff --git a/roundup/instance.py b/roundup/instance.py
index b87334065a9589cf2a5cc1ea4235b3e752010c0c..ec87f3899616e8997da61df4c5212d6d68fd093b 100644 (file)
--- a/roundup/instance.py
+++ b/roundup/instance.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: instance.py,v 1.9 2002-09-20 01:20:31 richard Exp $
+# $Id: instance.py,v 1.10 2003-09-04 00:47:01 richard Exp $
__doc__ = '''
Tracker handling (open tracker).
-Currently this module provides one function: open. This function opens
-a tracker. Note that trackers used to be called instances.
+Backwards compatibility for the old-style "imported" trackers.
'''
-import imp, os
+import os
+
+class Vars:
+ ''' I'm just a container '''
+
+class Tracker:
+ def __init__(self, tracker_home):
+ self.tracker_home = tracker_home
+ self.select_db = self._load_python('select_db.py')
+ self.config = self._load_config('config.py')
+ raise NotImplemented, 'this is *so* not finished'
+ self.init = XXX
+ self.Client = XXX
+ self.MailGW = XXX
+
+ def open(self):
+ return self._load_config('schema.py').db
+ self._load_config('security.py', db=db)
+
+
+ def __load_python(self, file):
+ file = os.path.join(tracker_home, file)
+ vars = Vars()
+ execfile(file, vars.__dict__)
+ return vars
+
class TrackerError(Exception):
pass
-class Opener:
+
+class OldStyleTrackers:
def __init__(self):
self.number = 0
self.trackers = {}
Raise ValueError if the tracker home doesn't exist.
'''
+ import imp
# sanity check existence of tracker home
if not os.path.exists(tracker_home):
raise ValueError, 'no such directory: "%s"'%tracker_home
return tracker
-opener = Opener()
-open = opener.open
-
-del Opener
-del opener
+OldStyleTrackers = OldStyleTrackers()
+def open(tracker_home):
+ if os.path.exists(os.path.join(tracker_home, 'dbinit.py')):
+ # user should upgrade...
+ return OldStyleTrackers.open(tracker_home)
+ return Tracker(tracker_home)
# vim: set filetype=python ts=4 sw=4 et si
diff --git a/templates/classic/detectors/nosyreaction.py b/templates/classic/detectors/nosyreaction.py
index 2c292041105c5cb76e5622dd92ff4d23a4f24871..750621112e90d4bed5261cbfbf0158c930b04658 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: nosyreaction.py,v 1.1 2003-04-17 03:26:38 richard Exp $
+#$Id: nosyreaction.py,v 1.2 2003-09-04 00:47:01 richard Exp $
from roundup import roundupdb, hyperdb
else:
ok = ('yes',)
# figure which of the messages now on the issue weren't
- # there before - make sure we don't get a cached version!
- oldmessages = cl.get(nodeid, 'messages', cache=0)
+ # there before
+ oldmessages = cl.get(nodeid, 'messages')
messages = []
for msgid in newvalues['messages']:
if msgid not in oldmessages:
diff --git a/templates/classic/detectors/statusauditor.py b/templates/classic/detectors/statusauditor.py
index f1ce29b03aa91e9e62a8d907c9beee05a8ca4423..e7aa6e9b02a4dd2c242d83a55bec495af040bdac 100644 (file)
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
-#$Id: statusauditor.py,v 1.2 2003-06-25 09:49:34 neaj Exp $
+#$Id: statusauditor.py,v 1.3 2003-09-04 00:47:01 richard Exp $
def chatty(db, cl, nodeid, newvalues):
''' If the issue is currently 'unread', 'resolved' or 'done-cbb', then set
# don't fire if there's no new message (ie. chat)
if not newvalues.has_key('messages'):
return
- if newvalues['messages'] == cl.get(nodeid, 'messages', cache=0):
+ if newvalues['messages'] == cl.get(nodeid, 'messages'):
return
# get the chatting state ID
diff --git a/test/test_db.py b/test/test_db.py
index 29942138ea77b964fbdee547e0fd091e8af5a1cd..9b16434c0c7181dcd9e5b8781d336a59d294df98 100644 (file)
--- a/test/test_db.py
+++ b/test/test_db.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: test_db.py,v 1.90 2003-08-12 02:22:22 richard Exp $
+# $Id: test_db.py,v 1.91 2003-09-04 00:47:01 richard Exp $
import unittest, os, shutil, time
self.assertNotEqual(a, self.db.status.list())
# try to restore retired node
self.db.status.restore('1')
- self.assertEqual(a, self.db.status.list())
+
+ def testCacheCreateSet(self):
+ self.db.issue.create(title="spam", status='1')
+ a = self.db.issue.get('1', 'title')
+ self.assertEqual(a, 'spam')
+ self.db.issue.set('1', title='ham')
+ b = self.db.issue.get('1', 'title')
+ self.assertEqual(b, 'ham')
def testSerialisation(self):
nid = self.db.issue.create(title="spam", status='1',