Mercurial > p > roundup > code
changeset 2005:fc52d57c6c3e
documentation cleanup
line wrap: on
line diff
--- a/TODO.txt Wed Feb 11 21:34:31 2004 +0000 +++ b/TODO.txt Wed Feb 11 23:55:10 2004 +0000 @@ -1,7 +1,10 @@ This file has been re-purposed to contain specifically the items that need doing before the next release: +- sessions, otks and indexing in RDBMSes - add tests for group-by-multilink so I finally implement it for the RDBMSes - full coverage analysis for unit tests +- s/getnode/getitem in backends (and s/Node/Item) +- activity_by meta-property + - migrate to numeric ID values (fixes bug 817217) -
--- a/doc/.cvsignore Wed Feb 11 21:34:31 2004 +0000 +++ b/doc/.cvsignore Wed Feb 11 23:55:10 2004 +0000 @@ -11,7 +11,7 @@ upgrading.html glossary.html design.html -maintenance.html +admin_guide.html overview.html mysql.html postgresql.html
--- a/doc/admin_guide.txt Wed Feb 11 21:34:31 2004 +0000 +++ b/doc/admin_guide.txt Wed Feb 11 23:55:10 2004 +0000 @@ -2,7 +2,7 @@ Administration Guide ==================== -:Version: $Revision: 1.1 $ +:Version: $Revision: 1.2 $ .. contents:: @@ -23,7 +23,7 @@ Support files <python dir>\share\roundup\... - and on *nix (eg. Linux): + and on Unix-like systems (eg. Linux): Scripts <python root>/bin/... @@ -84,7 +84,7 @@ 1. `tracker backup`_ 2. `software upgrade`_ 3. `migrating backends`_ -3. `moving a tracker`_ +4. `moving a tracker`_ Tracker Backup
--- a/roundup/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,9 +15,9 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: __init__.py,v 1.26 2004-01-20 00:05:07 richard Exp $ +# $Id: __init__.py,v 1.27 2004-02-11 23:55:08 richard Exp $ -''' Roundup - issue tracking for knowledge workers. +'''Roundup - issue tracking for knowledge workers. This is a simple-to-use and -install issue-tracking system with command-line, web and e-mail interfaces. @@ -43,11 +43,11 @@ | Storage Layer | ------------------------------------------------------------------------- -The first layer represents the users (chocolate). -The second layer is the Roundup interface to the users (vanilla). -The third and fourth layers are the internal Roundup database storage - mechanisms (strawberry). -The final, lowest layer is the underlying database storage (rum). +1. The first layer represents the users (chocolate). +2. The second layer is the Roundup interface to the users (vanilla). +3. The third and fourth layers are the internal Roundup database storage + mechanisms (strawberry). +4. The final, lowest layer is the underlying database storage (rum). These are implemented in the code in the following manner:: @@ -66,6 +66,7 @@ written by Ka-Ping Yee in the "doc" directory. If nothing else, it has a much prettier cake :) ''' +__docformat__ = 'restructuredtext' __version__ = '0.7.0b1'
--- a/roundup/admin.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/admin.py Wed Feb 11 23:55:10 2004 +0000 @@ -16,10 +16,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: admin.py,v 1.61 2003-11-13 04:12:10 richard Exp $ +# $Id: admin.py,v 1.62 2004-02-11 23:55:08 richard Exp $ '''Administration commands for maintaining Roundup trackers. ''' +__docformat__ = 'restructuredtext' import sys, os, getpass, getopt, re, UserDict, shutil, rfc822 from roundup import date, hyperdb, roundupdb, init, password, token, rcsv @@ -826,6 +827,7 @@ specified, all properties are displayed. By default, the column widths are the width of the largest value. The width may be explicitly defined by defining the property as "name:width". For example:: + roundup> table priority id,name:10 Id Name 1 fatal-bug @@ -834,7 +836,8 @@ 4 feature Also to make the width of the column the width of the label, - leave a trailing : without a width on the property. E.G. + leave a trailing : without a width on the property. For example:: + roundup> table priority id,name: Id Name 1 fata
--- a/roundup/backends/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,13 +15,14 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: __init__.py,v 1.25 2003-10-25 22:53:26 richard Exp $ +# $Id: __init__.py,v 1.26 2004-02-11 23:55:08 richard Exp $ -''' Container for the hyperdb storage backend implementations. +'''Container for the hyperdb storage backend implementations. The __all__ variable is constructed containing only the backends which are available. ''' +__docformat__ = 'restructuredtext' __all__ = []
--- a/roundup/backends/back_anydbm.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_anydbm.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,13 +15,13 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_anydbm.py,v 1.134 2003-12-10 01:40:51 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 +#$Id: back_anydbm.py,v 1.135 2004-02-11 23:55:08 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 versions >2.1.1 (the dumbdbm fallback in 2.1.1 and earlier has several serious bugs, and is not available) ''' +__docformat__ = 'restructuredtext' try: import anydbm, sys @@ -50,10 +50,10 @@ '''A database for storing records containing flexible data types. Transaction stuff TODO: - . check the timestamp of the class file and nuke the cache if it's - modified. Do some sort of conflict checking on the dirty stuff. - . perhaps detect write collisions (related to above)? - + + - check the timestamp of the class file and nuke the cache if it's + modified. Do some sort of conflict checking on the dirty stuff. + - perhaps detect write collisions (related to above)? ''' def __init__(self, config, journaltag=None): '''Open a hyperdatabase given a specifier to some storage. @@ -92,14 +92,15 @@ self.lockfile.flush() def post_init(self): - ''' Called once the schema initialisation has finished. + '''Called once the schema initialisation has finished. ''' # reindex the db if necessary if self.indexer.should_reindex(): self.reindex() def refresh_database(self): - "Rebuild the database" + """Rebuild the database + """ self.reindex() def reindex(self): @@ -1366,8 +1367,11 @@ WARNING: this method should never be used except in extremely rare situations where there could never be links to the node being deleted + WARNING: use retire() instead + WARNING: the properties of this node will not be available ever again + WARNING: really, use retire() instead Well, I think that's enough warnings. This method exists mostly to @@ -1418,14 +1422,15 @@ return self.key def labelprop(self, default_to_id=0): - ''' Return the property name for a label for the given node. + '''Return the property name for a label for the given node. This method attempts to generate a consistent label for the node. It tries the following in order: - 1. key property - 2. "name" property - 3. "title" property - 4. first property from the sorted property name list + + 1. key property + 2. "name" property + 3. "title" property + 4. first property from the sorted property name list ''' k = self.getkey() if k: @@ -1597,21 +1602,23 @@ def filter(self, search_matches, filterspec, sort=(None,None), group=(None,None), num_re = re.compile('^\d+$')): - ''' Return a list of the ids of the active nodes in this class that - match the 'filter' spec, sorted by the group spec and then the - sort spec. + """Return a list of the ids of the active nodes in this class that + match the 'filter' spec, sorted by the group spec and then the + sort spec. + + "filterspec" is {propname: value(s)} + + "sort" and "group" are (dir, prop) where dir is '+', '-' or None + and prop is a prop name or None - "filterspec" is {propname: value(s)} - "sort" and "group" are (dir, prop) where dir is '+', '-' or None - and prop is a prop name or None - "search_matches" is {nodeid: marker} + "search_matches" is {nodeid: marker} - The filter must match all properties specificed - but if the - property value to match is a list, any one of the values in the - list may match for that property to match. Unless the property - is a Multilink, in which case the item's property list must - match the filterspec list. - ''' + The filter must match all properties specificed - but if the + property value to match is a list, any one of the values in the + list may match for that property to match. Unless the property + is a Multilink, in which case the item's property list must + match the filterspec list. + """ cn = self.classname # optimise filterspec
--- a/roundup/backends/back_bsddb.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_bsddb.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,10 +15,10 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb.py,v 1.28 2003-11-14 00:11:18 richard Exp $ +#$Id: back_bsddb.py,v 1.29 2004-02-11 23:55:08 richard Exp $ +'''This module defines a backend that saves the hyperdatabase in BSDDB. ''' -This module defines a backend that saves the hyperdatabase in BSDDB. -''' +__docformat__ = 'restructuredtext' import bsddb, os, marshal from roundup import hyperdb, date
--- a/roundup/backends/back_bsddb3.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_bsddb3.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,10 +15,10 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: back_bsddb3.py,v 1.21 2003-11-14 00:11:18 richard Exp $ +#$Id: back_bsddb3.py,v 1.22 2004-02-11 23:55:08 richard Exp $ +'''This module defines a backend that saves the hyperdatabase in BSDDB3. ''' -This module defines a backend that saves the hyperdatabase in BSDDB3. -''' +__docformat__ = 'restructuredtext' import bsddb3, os, marshal from roundup import hyperdb, date
--- a/roundup/backends/back_metakit.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_metakit.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,110 +1,45 @@ -# $Id: back_metakit.py,v 1.57 2004-01-27 18:10:48 wc2so1 Exp $ -''' - Metakit backend for Roundup, originally by Gordon McMillan. +# $Id: back_metakit.py,v 1.58 2004-02-11 23:55:08 richard Exp $ +'''Metakit backend for Roundup, originally by Gordon McMillan. - Notes by Richard: - - This backend has some behaviour specific to metakit: - - - there's no concept of an explicit "unset" in metakit, so all types - have some "unset" value: +Known Current Bugs: - ========= ===== ==================================================== - Type Value Action when fetching from mk - ========= ===== ==================================================== - Strings '' convert to None - Date 0 (seconds since 1970-01-01.00:00:00) convert to None - Interval '' convert to None - Number 0 ambiguious :( - do nothing (see BACKWARDS_COMPATIBLE) - Boolean 0 ambiguious :( - do nothing (see BACKWARDS_COMPATABILE) - Link 0 convert to None - Multilink [] actually, mk can handle this one ;) - Password '' convert to None - ========= ===== ==================================================== +- You can't change a class' key properly. This shouldn't be too hard to fix. +- Some unit tests are overridden. + +Notes by Richard: - The get/set routines handle these values accordingly by converting - to/from None where they can. The Number/Boolean types are not able - to handle an "unset" at all, so they default the "unset" to 0. +This backend has some behaviour specific to metakit: - Metakit relies in reference counting to close the database, there is - no explicit close call. This can cause issues if a metakit - database is referenced multiple times, one might not actually be - closing the db. - - - probably a bunch of stuff that I'm not aware of yet because I haven't - fully read through the source. One of these days.... -''' -# Enable this flag to break backwards compatibility (i.e. can't read old databases) -# but comply with more roundup features, like adding NULL support. -BACKWARDS_COMPATIBLE = True +- there's no concept of an explicit "unset" in metakit, so all types + have some "unset" value: -# Changes to version 1.55: -# 1 Added an explicit close to the Indexer class. This was handled -# by garbage collection before. -# -# 2 Added an MKBackendError exception that gets thrown on some metakit errors. -# Should there be a general rdbms exception? -# -# 3 Added a sanity check when creating metakit tables in __getview -# There are some test cases that create columns of the same name -# with different metakit types. This can cause crashing issues with -# older version of metakit. We catch these before hand and raise -# an exception. -# -# 4 metakit db's cannot be weakref'd so this was removed -# -# 5 fixed a metakit.append, metakit must append lists, objects or -# dictionaries, it can't handle scalars. -# sv.append(int(entry)) -# became -# sv.append((int(entry),)) -# -# 6 To make it easier to compare to the other backends -# Class.keyname is changed to Class.key -# -# 7 Fixed Class.lookup, sometimes it would claim that a valid -# row was not valid (an _isdel row _property of 0 would -# be reported as 1) This is because metakit's view.find -# operation was returning bad results. This should be -# view.select or view.find on a single property. -# -# 8 calling create with no parameters raises a value error -# I'm not sure if this is appropriate, but it fixes -# a regression test :) -# -# 9 The get method was only converting results for commited -# values. uncommited values were not being converted -# using the metakit conversion table -# -# 10 Added a check to the Class.__init__ to raise a ValueError -# if the database already has a class of the same name. -# -# 11 Boolean and Number types can now have null values. This -# is a backwards incompatible fix in that old databases -# won't work correctly. -# -# The fix is simple. For a boolean column, 0 is now None -# 1 is False (returns 0) -# 2 is True (returns 1) -# For a numeric column, 0 is now None -# values 0 get returned as value-1 -# values < 0 get returned as value -# Set the BACKWARDS_COMPATIBLE flag to False to enable this fix. -# -# 12 Enumerated READ and READWRITE for the getview and getindexedview -# These will probably be removed because they are not used -# -# Changed to 1.56 -# -# 13 worked-around a current metakit bug, so retiring properties now -# works correctly. -# metakit 2.9.2 has a bug when using "find" on ordered views, -# using multiple arguments for find doesn't work. -# -# Known Current Bugs: -# You can't change a class' key properly. -# This shouldn't be too hard to fix. -# + ========= ===== ====================================================== + Type Value Action when fetching from mk + ========= ===== ====================================================== + Strings '' convert to None + Date 0 (seconds since 1970-01-01.00:00:00) convert to None + Interval '' convert to None + Number 0 ambiguious :( - do nothing (see BACKWARDS_COMPATIBLE) + Boolean 0 ambiguious :( - do nothing (see BACKWARDS_COMPATABILE) + Link 0 convert to None + Multilink [] actually, mk can handle this one ;) + Password '' convert to None + ========= ===== ====================================================== + + The get/set routines handle these values accordingly by converting + to/from None where they can. The Number/Boolean types are not able + to handle an "unset" at all, so they default the "unset" to 0. +- Metakit relies in reference counting to close the database, there is + no explicit close call. This can cause issues if a metakit + database is referenced multiple times, one might not actually be + closing the db. +- probably a bunch of stuff that I'm not aware of yet because I haven't + fully read through the source. One of these days.... +''' +__docformat__ = 'restructuredtext' +# Enable this flag to break backwards compatibility (i.e. can't read old +# databases) but comply with more roundup features, like adding NULL support. +BACKWARDS_COMPATIBLE = True from roundup import hyperdb, date, password, roundupdb, security import metakit @@ -940,18 +875,19 @@ def find(self, **propspec): """Get the ids of nodes in this class which link to the given nodes. - 'propspec' consists of keyword args propname={nodeid:1,} - 'propname' must be the name of a property in this class, or a - KeyError is raised. That property must be a Link or - Multilink property, or a TypeError is raised. + 'propspec' + consists of keyword args propname={nodeid:1,} + 'propname' + must be the name of a property in this class, or a + KeyError is raised. That property must be a Link or + Multilink property, or a TypeError is raised. Any node in this class whose propname property links to any of the nodeids will be returned. Used by the full text indexing, which knows that "foo" occurs in msg1, msg3 and file7; so we have hits on these - issues: + issues:: db.issue.find(messages={'1':1,'3':1}, files={'7':1}) - """ propspec = propspec.items() for propname, nodeid in propspec: @@ -1249,14 +1185,15 @@ return int(nodeid) < self.maxid def labelprop(self, default_to_id=0): - ''' Return the property name for a label for the given node. + '''Return the property name for a label for the given node. This method attempts to generate a consistent label for the node. It tries the following in order: - 1. key property - 2. "name" property - 3. "title" property - 4. first property from the sorted property name list + + 1. key property + 2. "name" property + 3. "title" property + 4. first property from the sorted property name list ''' k = self.getkey() if k:
--- a/roundup/backends/back_mysql.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_mysql.py Wed Feb 11 23:55:10 2004 +0000 @@ -5,8 +5,9 @@ # under the same terms as Python, so long as this copyright message and # disclaimer are retained in their original form. # -# Mysql backend for roundup -# + +'''This module defines a backend implementation for MySQL.''' +__docformat__ = 'restructuredtext' from roundup.backends.rdbms_common import * from roundup.backends import rdbms_common @@ -208,18 +209,20 @@ # look for "I can't believe it's not a toy RDBMS" below def filter(self, search_matches, filterspec, sort=(None,None), group=(None,None)): - ''' Return a list of the ids of the active nodes in this class that - match the 'filter' spec, sorted by the group spec and then the - sort spec + '''Return a list of the ids of the active nodes in this class that + match the 'filter' spec, sorted by the group spec and then the + sort spec + + "filterspec" is {propname: value(s)} - "filterspec" is {propname: value(s)} - "sort" and "group" are (dir, prop) where dir is '+', '-' or None - and prop is a prop name or None - "search_matches" is {nodeid: marker} + "sort" and "group" are (dir, prop) where dir is '+', '-' or None + and prop is a prop name or None - The filter must match all properties specificed - but if the - property value to match is a list, any one of the values in the - list may match for that property to match. + "search_matches" is {nodeid: marker} + + The filter must match all properties specificed - but if the + property value to match is a list, any one of the values in the + list may match for that property to match. ''' # just don't bother if the full-text search matched diddly if search_matches == {}:
--- a/roundup/backends/back_postgresql.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_postgresql.py Wed Feb 11 23:55:10 2004 +0000 @@ -5,8 +5,9 @@ # under the same terms as Python, so long as this copyright message and # disclaimer are retained in their original form. # -# psycopg backend for roundup -# +'''Postgresql backend via psycopg for Roundup.''' +__docformat__ = 'restructuredtext' + from roundup import hyperdb, date from roundup.backends import rdbms_common
--- a/roundup/backends/back_sqlite.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/back_sqlite.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,7 +1,10 @@ -# $Id: back_sqlite.py,v 1.12 2003-11-12 01:00:58 richard Exp $ -__doc__ = ''' +# $Id: back_sqlite.py,v 1.13 2004-02-11 23:55:09 richard Exp $ +'''Implements a backend for SQLite. + See https://pysqlite.sourceforge.net/ for pysqlite info ''' +__docformat__ = 'restructuredtext' + import os, base64, marshal from roundup import hyperdb
--- a/roundup/backends/blobfiles.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/blobfiles.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -#$Id: blobfiles.py,v 1.10 2003-12-05 03:28:38 richard Exp $ -''' -This module exports file storage for roundup backends. +#$Id: blobfiles.py,v 1.11 2004-02-11 23:55:09 richard Exp $ +'''This module exports file storage for roundup backends. Files are stored into a directory hierarchy. ''' +__docformat__ = 'restructuredtext' import os
--- a/roundup/backends/locking.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/locking.py Wed Feb 11 23:55:10 2004 +0000 @@ -19,13 +19,14 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -# $Id: locking.py,v 1.7 2003-07-03 23:43:46 richard Exp $ +# $Id: locking.py,v 1.8 2004-02-11 23:55:09 richard Exp $ '''This module provides a generic interface to acquire and release exclusive access to a file. It should work on Unix and Windows. ''' +__docformat__ = 'restructuredtext' import portalocker
--- a/roundup/backends/portalocker.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/portalocker.py Wed Feb 11 23:55:10 2004 +0000 @@ -2,11 +2,11 @@ # Requires python 1.5.2 or better. # ID line added by richard for Roundup file tracking -# $Id: portalocker.py,v 1.7 2003-08-26 00:29:20 richard Exp $ +# $Id: portalocker.py,v 1.8 2004-02-11 23:55:09 richard Exp $ -""" Cross-platform (posix/nt) API for flock-style file locking. +"""Cross-platform (posix/nt) API for flock-style file locking. -Synopsis: +Synopsis:: import portalocker file = open("somefile", "r+") @@ -15,18 +15,18 @@ file.write("foo") file.close() -If you know what you're doing, you may choose to +If you know what you're doing, you may choose to:: portalocker.unlock(file) before closing the file, but why? -Methods: +Methods:: lock( file, flags ) unlock( file ) -Constants: +Constants:: LOCK_EX LOCK_SH @@ -36,10 +36,12 @@ provided by John Nielsen <nielsenjf@my-deja.com> in the documentation that accompanies the win32 modules. -Author: Jonathan Feinberg <jdf@pobox.com> -Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp - **un-cvsified by richard so the version doesn't change** +:Author: Jonathan Feinberg <jdf@pobox.com> +:Version: Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp + **un-cvsified by richard so the version doesn't change** """ +__docformat__ = 'restructuredtext' + import os if os.name == 'nt':
--- a/roundup/backends/rdbms_common.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/rdbms_common.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,4 +1,4 @@ -# $Id: rdbms_common.py,v 1.74 2004-01-20 05:55:51 richard Exp $ +# $Id: rdbms_common.py,v 1.75 2004-02-11 23:55:09 richard Exp $ ''' Relational database (SQL) backend common code. Basics: @@ -20,6 +20,7 @@ honors column typing, since the initial databases don't (sqlite stores everything as a string.) ''' +__docformat__ = 'restructuredtext' # standard python modules import sys, os, time, re, errno, weakref, copy @@ -490,10 +491,10 @@ raise KeyError, 'There is no class called "%s"'%classname def clear(self): - ''' Delete all database contents. + '''Delete all database contents. - Note: I don't commit here, which is different behaviour to the - "nuke from orbit" behaviour in the *dbms. + Note: I don't commit here, which is different behaviour to the + "nuke from orbit" behaviour in the dbs. ''' if __debug__: print >>hyperdb.DEBUG, 'clear', (self,) @@ -1649,8 +1650,11 @@ WARNING: this method should never be used except in extremely rare situations where there could never be links to the node being deleted + WARNING: use retire() instead + WARNING: the properties of this node will not be available ever again + WARNING: really, use retire() instead Well, I think that's enough warnings. This method exists mostly to @@ -1706,14 +1710,15 @@ return self.key def labelprop(self, default_to_id=0): - ''' Return the property name for a label for the given node. + '''Return the property name for a label for the given node. This method attempts to generate a consistent label for the node. It tries the following in order: - 1. key property - 2. "name" property - 3. "title" property - 4. first property from the sorted property name list + + 1. key property + 2. "name" property + 3. "title" property + 4. first property from the sorted property name list ''' k = self.getkey() if k: @@ -1897,18 +1902,20 @@ def filter(self, search_matches, filterspec, sort=(None,None), group=(None,None)): - ''' Return a list of the ids of the active nodes in this class that - match the 'filter' spec, sorted by the group spec and then the - sort spec + '''Return a list of the ids of the active nodes in this class that + match the 'filter' spec, sorted by the group spec and then the + sort spec + + "filterspec" is {propname: value(s)} - "filterspec" is {propname: value(s)} - "sort" and "group" are (dir, prop) where dir is '+', '-' or None - and prop is a prop name or None - "search_matches" is {nodeid: marker} + "sort" and "group" are (dir, prop) where dir is '+', '-' or None + and prop is a prop name or None - The filter must match all properties specificed - but if the - property value to match is a list, any one of the values in the - list may match for that property to match. + "search_matches" is {nodeid: marker} + + The filter must match all properties specificed - but if the + property value to match is a list, any one of the values in the + list may match for that property to match. ''' # just don't bother if the full-text search matched diddly if search_matches == {}:
--- a/roundup/backends/sessions.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/backends/sessions.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,12 +1,11 @@ -#$Id: sessions.py,v 1.6 2003-09-05 21:05:18 jlgijsbers Exp $ -""" -This module defines a very basic store that's used by the CGI interface +#$Id: sessions.py,v 1.7 2004-02-11 23:55:09 richard Exp $ +"""This module defines a very basic store that's used by the CGI interface to store session and one-time-key information. Yes, it's called "sessions" - because originally it only defined a session class. It's now also used for One Time Key handling too. - """ +__docformat__ = 'restructuredtext' import anydbm, whichdb, os, marshal
--- a/roundup/cgi/PageTemplates/Expressions.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/Expressions.py Wed Feb 11 23:55:10 2004 +0000 @@ -24,8 +24,9 @@ - Made traceback info more informative """ +__docformat__ = 'restructuredtext' -__version__='$Revision: 1.8 $'[11:-2] +__version__='$Revision: 1.9 $'[11:-2] import re, sys from TALES import Engine, CompilerError, _valid_name, NAME_RE, \
--- a/roundup/cgi/PageTemplates/PageTemplate.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/PageTemplate.py Wed Feb 11 23:55:10 2004 +0000 @@ -20,8 +20,9 @@ - changed imports to import from roundup.cgi """ +__docformat__ = 'restructuredtext' -__version__='$Revision: 1.3 $'[11:-2] +__version__='$Revision: 1.4 $'[11:-2] import sys
--- a/roundup/cgi/PageTemplates/PathIterator.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/PathIterator.py Wed Feb 11 23:55:10 2004 +0000 @@ -16,8 +16,9 @@ A TALES Iterator with the ability to use first() and last() on subpaths of elements. """ +__docformat__ = 'restructuredtext' -__version__='$Revision: 1.1 $'[11:-2] +__version__='$Revision: 1.2 $'[11:-2] import TALES from Expressions import restrictedTraverse, Undefs, getSecurityManager
--- a/roundup/cgi/PageTemplates/PythonExpr.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/PythonExpr.py Wed Feb 11 23:55:10 2004 +0000 @@ -18,8 +18,9 @@ - more informative traceback info """ +__docformat__ = 'restructuredtext' -__version__='$Revision: 1.4 $'[11:-2] +__version__='$Revision: 1.5 $'[11:-2] from TALES import CompilerError from string import strip, split, join, replace, lstrip
--- a/roundup/cgi/PageTemplates/TALES.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/TALES.py Wed Feb 11 23:55:10 2004 +0000 @@ -18,8 +18,9 @@ - changed imports to import from roundup.cgi """ +__docformat__ = 'restructuredtext' -__version__='$Revision: 1.5 $'[11:-2] +__version__='$Revision: 1.6 $'[11:-2] import re, sys from roundup.cgi import ZTUtils
--- a/roundup/cgi/PageTemplates/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/PageTemplates/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,7 +15,8 @@ This wrapper allows the Page Template modules to be segregated in a separate package. -$Id: __init__.py,v 1.1 2002-09-05 00:37:09 richard Exp $''' +$Id: __init__.py,v 1.2 2004-02-11 23:55:09 richard Exp $''' +__docformat__ = 'restructuredtext' __version__='$$'[11:-2]
--- a/roundup/cgi/TAL/HTMLParser.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/HTMLParser.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,4 +1,5 @@ """A parser for HTML and XHTML.""" +__docformat__ = 'restructuredtext' # This file is based on sgmllib.py, but the API is slightly different.
--- a/roundup/cgi/TAL/HTMLTALParser.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/HTMLTALParser.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,9 +11,9 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## +"""Parse HTML and compile to TALInterpreter intermediate code. """ -Parse HTML and compile to TALInterpreter intermediate code. -""" +__docformat__ = 'restructuredtext' import sys import string
--- a/roundup/cgi/TAL/TALDefs.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/TALDefs.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,9 +11,9 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## +"""Common definitions used by TAL and METAL compilation an transformation. """ -Common definitions used by TAL and METAL compilation an transformation. -""" +__docformat__ = 'restructuredtext' from types import ListType, TupleType
--- a/roundup/cgi/TAL/TALGenerator.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/TALGenerator.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,9 +11,9 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## +"""Code generator for TALInterpreter intermediate code. """ -Code generator for TALInterpreter intermediate code. -""" +__docformat__ = 'restructuredtext' import string import re
--- a/roundup/cgi/TAL/TALInterpreter.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/TALInterpreter.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,9 +11,9 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## +"""Interpreter for a pre-compiled TAL program. """ -Interpreter for a pre-compiled TAL program. -""" +__docformat__ = 'restructuredtext' import sys import getopt
--- a/roundup/cgi/TAL/TALParser.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/TALParser.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,9 +11,9 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## +"""Parse XML and compile to TALInterpreter intermediate code. """ -Parse XML and compile to TALInterpreter intermediate code. -""" +__docformat__ = 'restructuredtext' import string from XMLParser import XMLParser
--- a/roundup/cgi/TAL/XMLParser.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/XMLParser.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,14 +11,14 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## -""" -Generic expat-based XML parser base class. +"""Generic expat-based XML parser base class. Modified for Roundup 0.5 release: - removed dependency on zLOG """ +__docformat__ = 'restructuredtext' class XMLParser:
--- a/roundup/cgi/TAL/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -11,4 +11,5 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## -""" Template Attribute Language package """ +"""Template Attribute Language package """ +__docformat__ = 'restructuredtext'
--- a/roundup/cgi/TAL/markupbase.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/TAL/markupbase.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,4 +1,6 @@ -"""Shared support for scanning document type declarations in HTML and XHTML.""" +"""Shared support for scanning document type declarations in HTML and XHTML. +""" +__docformat__ = 'restructuredtext' import re import string
--- a/roundup/cgi/ZTUtils/Batch.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/ZTUtils/Batch.py Wed Feb 11 23:55:10 2004 +0000 @@ -12,8 +12,9 @@ ############################################################################## __doc__='''Batch class, for iterating over a sequence in batches -$Id: Batch.py,v 1.2 2002-09-11 23:54:26 richard Exp $''' -__version__='$Revision: 1.2 $'[11:-2] +$Id: Batch.py,v 1.3 2004-02-11 23:55:09 richard Exp $''' +__docformat__ = 'restructuredtext' +__version__='$Revision: 1.3 $'[11:-2] class LazyPrevBatch: def __of__(self, parent):
--- a/roundup/cgi/ZTUtils/Iterator.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/ZTUtils/Iterator.py Wed Feb 11 23:55:10 2004 +0000 @@ -18,8 +18,9 @@ iterator. The next() method fetches the next item, and returns true if it succeeds. -$Id: Iterator.py,v 1.2 2002-09-26 21:54:17 richard Exp $''' -__version__='$Revision: 1.2 $'[11:-2] +$Id: Iterator.py,v 1.3 2004-02-11 23:55:09 richard Exp $''' +__docformat__ = 'restructuredtext' +__version__='$Revision: 1.3 $'[11:-2] import string
--- a/roundup/cgi/ZTUtils/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/ZTUtils/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -16,8 +16,9 @@ - removed Zope imports -$Id: __init__.py,v 1.2 2002-09-07 22:42:47 richard Exp $''' -__version__='$Revision: 1.2 $'[11:-2] +$Id: __init__.py,v 1.3 2004-02-11 23:55:09 richard Exp $''' +__docformat__ = 'restructuredtext' +__version__='$Revision: 1.3 $'[11:-2] from Batch import Batch from Iterator import Iterator
--- a/roundup/cgi/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,1 +1,2 @@ -' CGI interface modules ' +''' CGI interface modules ''' +__docformat__ = 'restructuredtext'
--- a/roundup/cgi/cgitb.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/cgitb.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,11 +1,11 @@ # # This module was written by Ka-Ping Yee, <ping@lfw.org>. # -# $Id: cgitb.py,v 1.9 2003-12-05 03:36:34 richard Exp $ +# $Id: cgitb.py,v 1.10 2004-02-11 23:55:09 richard Exp $ -__doc__ = """ -Extended CGI traceback handler by Ka-Ping Yee, <ping@lfw.org>. +"""Extended CGI traceback handler by Ka-Ping Yee, <ping@lfw.org>. """ +__docformat__ = 'restructuredtext' import sys, os, types, string, keyword, linecache, tokenize, inspect, cgi import pydoc, traceback
--- a/roundup/cgi/client.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/client.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,8 +1,8 @@ -# $Id: client.py,v 1.155 2004-02-11 21:34:31 jlgijsbers Exp $ +# $Id: client.py,v 1.156 2004-02-11 23:55:09 richard Exp $ -__doc__ = """ -WWW request handler (also used in the stand-alone server). +"""WWW request handler (also used in the stand-alone server). """ +__docformat__ = 'restructuredtext' import os, os.path, cgi, StringIO, urlparse, re, traceback, mimetypes, urllib import binascii, Cookie, time, random, stat, rfc822 @@ -16,10 +16,10 @@ from roundup.mailer import Mailer, MessageSendError def initialiseSecurity(security): - ''' Create some Permissions and Roles on the security object + '''Create some Permissions and Roles on the security object - This function is directly invoked by security.Security.__init__() - as a part of the Security object instantiation. + This function is directly invoked by security.Security.__init__() + as a part of the Security object instantiation. ''' security.addPermission(name="Web Registration", description="User may register through the web") @@ -46,28 +46,30 @@ return '<%s>'%match.group(2) class Client: - ''' Instantiate to handle one CGI request. + '''Instantiate to handle one CGI request. See inner_main for request processing. Client attributes at instantiation: - "path" is the PATH_INFO inside the instance (with no leading '/') - "base" is the base URL for the instance - "form" is the cgi form, an instance of FieldStorage from the standard - cgi module - "additional_headers" is a dictionary of additional HTTP headers that - should be sent to the client - "response_code" is the HTTP response code to send to the client + + - "path" is the PATH_INFO inside the instance (with no leading '/') + - "base" is the base URL for the instance + - "form" is the cgi form, an instance of FieldStorage from the standard + cgi module + - "additional_headers" is a dictionary of additional HTTP headers that + should be sent to the client + - "response_code" is the HTTP response code to send to the client During the processing of a request, the following attributes are used: - "error_message" holds a list of error messages - "ok_message" holds a list of OK messages - "session" is the current user session id - "user" is the current user's name - "userid" is the current user's id - "template" is the current :template context - "classname" is the current class context name - "nodeid" is the current context item id + + - "error_message" holds a list of error messages + - "ok_message" holds a list of OK messages + - "session" is the current user session id + - "user" is the current user's name + - "userid" is the current user's id + - "template" is the current :template context + - "classname" is the current class context name + - "nodeid" is the current context item id User Identification: If the user has no login cookie, then they are anonymous and are logged @@ -77,7 +79,6 @@ Once a user logs in, they are assigned a session. The Client instance keeps the nodeid of the session as the "session" attribute. - Special form variables: Note that in various places throughout this code, special form variables of the form :<name> are used. The colon (":") part may @@ -146,32 +147,34 @@ self.db.close() def inner_main(self): - ''' Process a request. + '''Process a request. + + The most common requests are handled like so: - The most common requests are handled like so: - 1. figure out who we are, defaulting to the "anonymous" user - see determine_user - 2. figure out what the request is for - the context - see determine_context - 3. handle any requested action (item edit, search, ...) - see handle_action - 4. render a template, resulting in HTML output + 1. figure out who we are, defaulting to the "anonymous" user + see determine_user + 2. figure out what the request is for - the context + see determine_context + 3. handle any requested action (item edit, search, ...) + see handle_action + 4. render a template, resulting in HTML output + + In some situations, exceptions occur: - In some situations, exceptions occur: - - HTTP Redirect (generally raised by an action) - - SendFile (generally raised by determine_context) - serve up a FileClass "content" property - - SendStaticFile (generally raised by determine_context) - serve up a file from the tracker "html" directory - - Unauthorised (generally raised by an action) - the action is cancelled, the request is rendered and an error - message is displayed indicating that permission was not - granted for the action to take place - - templating.Unauthorised (templating action not permitted) - raised by an attempted rendering of a template when the user - doesn't have permission - - NotFound (raised wherever it needs to be) - percolates up to the CGI interface that called the client + - HTTP Redirect (generally raised by an action) + - SendFile (generally raised by determine_context) + serve up a FileClass "content" property + - SendStaticFile (generally raised by determine_context) + serve up a file from the tracker "html" directory + - Unauthorised (generally raised by an action) + the action is cancelled, the request is rendered and an error + message is displayed indicating that permission was not + granted for the action to take place + - templating.Unauthorised (templating action not permitted) + raised by an attempted rendering of a template when the user + doesn't have permission + - NotFound (raised wherever it needs to be) + percolates up to the CGI interface that called the client ''' self.ok_message = [] self.error_message = [] @@ -262,22 +265,25 @@ sessions.set('last_clean', last_use=time.time()) def determine_user(self): - '''Determine who the user is. + ''' Determine who the user is ''' - # open the database as admin + # determine the uid to use self.opendb('admin') - # clean age sessions + # make sure we have the session Class self.clean_sessions() - - # make sure we have the session Class sessions = self.db.sessions - # look up the user session cookie - cookie = Cookie.SimpleCookie(self.env.get('HTTP_COOKIE', '')) + # first up, try the REMOTE_USER var (from HTTP Basic Auth handled + # by a front-end HTTP server) + try: + user = os.getenv('REMOTE_USER') + except KeyError: + pass + + # look up the user session cookie (may override the REMOTE_USER) + cookie = Cookie.Cookie(self.env.get('HTTP_COOKIE', '')) user = 'anonymous' - - # bump the "revision" of the cookie since the format changed if (cookie.has_key(self.cookie_name) and cookie[self.cookie_name].value != 'deleted'): @@ -290,7 +296,8 @@ sessions.commit() user = sessions.get(self.session, 'user') except KeyError: - user = 'anonymous' + # not valid, ignore id + pass # sanity check on the user still being valid, getting the userid # at the same time @@ -309,40 +316,43 @@ self.opendb(self.user) def determine_context(self, dre=re.compile(r'([^\d]+)(\d+)')): - """ Determine the context of this page from the URL: + """Determine the context of this page from the URL: - The URL path after the instance identifier is examined. The path - is generally only one entry long. + The URL path after the instance identifier is examined. The path + is generally only one entry long. - - if there is no path, then we are in the "home" context. - * if the path is "_file", then the additional path entry - specifies the filename of a static file we're to serve up - from the instance "html" directory. Raises a SendStaticFile - exception. - - if there is something in the path (eg "issue"), it identifies - the tracker class we're to display. - - if the path is an item designator (eg "issue123"), then we're - to display a specific item. - * if the path starts with an item designator and is longer than - one entry, then we're assumed to be handling an item of a - FileClass, and the extra path information gives the filename - that the client is going to label the download with (ie - "file123/image.png" is nicer to download than "file123"). This - raises a SendFile exception. + - if there is no path, then we are in the "home" context. + - if the path is "_file", then the additional path entry + specifies the filename of a static file we're to serve up + from the instance "html" directory. Raises a SendStaticFile + exception.(*) + - if there is something in the path (eg "issue"), it identifies + the tracker class we're to display. + - if the path is an item designator (eg "issue123"), then we're + to display a specific item. + - if the path starts with an item designator and is longer than + one entry, then we're assumed to be handling an item of a + FileClass, and the extra path information gives the filename + that the client is going to label the download with (ie + "file123/image.png" is nicer to download than "file123"). This + raises a SendFile exception.(*) - Both of the "*" types of contexts stop before we bother to - determine the template we're going to use. That's because they - don't actually use templates. + Both of the "*" types of contexts stop before we bother to + determine the template we're going to use. That's because they + don't actually use templates. - The template used is specified by the :template CGI variable, - which defaults to: + The template used is specified by the :template CGI variable, + which defaults to: - only classname suplied: "index" - full item designator supplied: "item" + - only classname suplied: "index" + - full item designator supplied: "item" + + We set: - We set: self.classname - the class to display, can be None + self.template - the template to render the current context with + self.nodeid - the nodeid of the class we're displaying """ # default the optional variables
--- a/roundup/cgi/templating.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/cgi/templating.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,3 +1,7 @@ +"""Implements the API used in the HTML templating for the web interface. +""" +__docformat__ = 'restructuredtext' + from __future__ import nested_scopes import sys, cgi, urllib, os, re, os.path, time, errno, mimetypes @@ -143,35 +147,37 @@ raise KeyError, message class RoundupPageTemplate(PageTemplate.PageTemplate): - ''' A Roundup-specific PageTemplate. + '''A Roundup-specific PageTemplate. + + Interrogate the client to set up the various template variables to + be available: + + *context* + this is one of three things: - Interrogate the client to set up the various template variables to - be available: + 1. None - we're viewing a "home" page + 2. The current class of item being displayed. This is an HTMLClass + instance. + 3. The current item from the database, if we're viewing a specific + item, as an HTMLItem instance. + *request* + Includes information about the current request, including: - *context* - this is one of three things: - 1. None - we're viewing a "home" page - 2. The current class of item being displayed. This is an HTMLClass - instance. - 3. The current item from the database, if we're viewing a specific - item, as an HTMLItem instance. - *request* - Includes information about the current request, including: - - the url - - the current index information (``filterspec``, ``filter`` args, - ``properties``, etc) parsed out of the form. - - methods for easy filterspec link generation - - *user*, the current user node as an HTMLItem instance - - *form*, the current CGI form information as a FieldStorage - *config* - The current tracker config. - *db* - The current database, used to access arbitrary database items. - *utils* - This is a special class that has its base in the TemplatingUtils - class in this file. If the tracker interfaces module defines a - TemplatingUtils class then it is mixed in, overriding the methods - in the base class. + - the url + - the current index information (``filterspec``, ``filter`` args, + ``properties``, etc) parsed out of the form. + - methods for easy filterspec link generation + - *user*, the current user node as an HTMLItem instance + - *form*, the current CGI form information as a FieldStorage + *config* + The current tracker config. + *db* + The current database, used to access arbitrary database items. + *utils* + This is a special class that has its base in the TemplatingUtils + class in this file. If the tracker interfaces module defines a + TemplatingUtils class then it is mixed in, overriding the methods + in the base class. ''' def getContext(self, client, classname, request): # construct the TemplatingUtils class @@ -962,11 +968,11 @@ return self.plain(hyperlink=1) def plain(self, escape=0, hyperlink=0): - ''' Render a "plain" representation of the property + '''Render a "plain" representation of the property - "escape" turns on/off HTML quoting - "hyperlink" turns on/off in-text hyperlinking of URLs, email - addresses and designators + - "escape" turns on/off HTML quoting + - "hyperlink" turns on/off in-text hyperlinking of URLs, email + addresses and designators ''' self.view_check() @@ -1441,7 +1447,7 @@ def __contains__(self, value): ''' Support the "in" operator. We have to make sure the passed-in - value is a string first, not a *HTMLProperty. + value is a string first, not a HTMLProperty. ''' return str(value) in self._value @@ -1601,25 +1607,25 @@ return self.columns.has_key(name) class HTMLRequest(HTMLInputMixin): - ''' The *request*, holding the CGI form and environment. + '''The *request*, holding the CGI form and environment. - "form" the CGI form as a cgi.FieldStorage - "env" the CGI environment variables - "base" the base URL for this instance - "user" a HTMLUser instance for this user - "classname" the current classname (possibly None) - "template" the current template (suffix, also possibly None) + - "form" the CGI form as a cgi.FieldStorage + - "env" the CGI environment variables + - "base" the base URL for this instance + - "user" a HTMLUser instance for this user + - "classname" the current classname (possibly None) + - "template" the current template (suffix, also possibly None) - Index args: - "columns" dictionary of the columns to display in an index page - "show" a convenience access to columns - request/show/colname will - be true if the columns should be displayed, false otherwise - "sort" index sort column (direction, column name) - "group" index grouping property (direction, column name) - "filter" properties to filter the index on - "filterspec" values to filter the index on - "search_text" text to perform a full-text search on for an index + Index args: + - "columns" dictionary of the columns to display in an index page + - "show" a convenience access to columns - request/show/colname will + be true if the columns should be displayed, false otherwise + - "sort" index sort column (direction, column name) + - "group" index grouping property (direction, column name) + - "filter" properties to filter the index on + - "filterspec" values to filter the index on + - "search_text" text to perform a full-text search on for an index ''' def __init__(self, client): # _client is needed by HTMLInputMixin
--- a/roundup/date.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/date.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: date.py,v 1.59 2003-12-05 03:28:38 richard Exp $ +# $Id: date.py,v 1.60 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ -Date, time and time interval handling. +"""Date, time and time interval handling. """ +__docformat__ = 'restructuredtext' import time, re, calendar, types from i18n import _ @@ -51,6 +51,7 @@ care of these conversions. In the following examples, suppose that yyyy is the current year, mm is the current month, and dd is the current day of the month; and suppose that the user is on Eastern Standard Time. + Examples:: "2000-04-17" means <Date 2000-04-17.00:00:00> "01-25" means <Date yyyy-01-25.00:00:00> @@ -69,9 +70,8 @@ separately. For example, when evaluating "2000-06-25 + 1m 10d", we first add one month to get 2000-07-25, then add 10 days to get 2000-08-04 (rather than trying to decide whether 1m 10d means 38 or 40 - or 41 days). + or 41 days). Example usage:: - Example usage: >>> Date(".") <Date 2000-06-26.00:34:02> >>> _.local(-5) @@ -95,9 +95,11 @@ def __init__(self, spec='.', offset=0, add_granularity=0): """Construct a date given a specification and a time zone offset. - 'spec' is a full date or a partial form, with an optional - added or subtracted interval. Or a date 9-tuple. - 'offset' is the local time zone offset from GMT in hours. + 'spec' + is a full date or a partial form, with an optional added or + subtracted interval. Or a date 9-tuple. + 'offset' + is the local time zone offset from GMT in hours. """ if type(spec) == type(''): self.set(spec, offset=offset, add_granularity=add_granularity) @@ -660,20 +662,24 @@ return (sign, y, m, d, H, M, S) class Range: - """ - Represents range between two values + """Represents range between two values Ranges can be created using one of theese two alternative syntaxes: - 1. Native english syntax: + 1. Native english syntax:: + [[From] <value>][ To <value>] - Keywords "From" and "To" are case insensitive. Keyword "From" is optional. + + Keywords "From" and "To" are case insensitive. Keyword "From" is + optional. - 2. "Geek" syntax: - [<value>][; <value>] + 2. "Geek" syntax:: + + [<value>][; <value>] Either first or second <value> can be omitted in both syntaxes. - Examples (consider local time is Sat Mar 8 22:07:48 EET 2003): + Examples (consider local time is Sat Mar 8 22:07:48 EET 2003):: + >>> Range("from 2-12 to 4-2") <Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
--- a/roundup/hyperdb.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/hyperdb.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: hyperdb.py,v 1.95 2003-11-16 22:56:46 jlgijsbers Exp $ +# $Id: hyperdb.py,v 1.96 2004-02-11 23:55:08 richard Exp $ +"""Hyperdatabase implementation, especially field types. """ -Hyperdatabase implementation, especially field types. -""" +__docformat__ = 'restructuredtext' # standard python modules import sys, os, time, re @@ -250,19 +250,19 @@ ''' return node - def getnode(self, classname, nodeid, db=None, cache=1): + def getnode(self, classname, nodeid): '''Get a node from the database. 'cache' exists for backwards compatibility, and is not used. ''' raise NotImplementedError - def hasnode(self, classname, nodeid, db=None): + def hasnode(self, classname, nodeid): '''Determine if the database has a given node. ''' raise NotImplementedError - def countnodes(self, classname, db=None): + def countnodes(self, classname): '''Count the number of nodes that exist for a particular Class. ''' raise NotImplementedError @@ -374,7 +374,7 @@ raise NotImplementedError # not in spec - def getnode(self, nodeid, cache=1): + def getnode(self, nodeid): ''' Return a convenience wrapper for the node. 'nodeid' must be the id of an existing node of this class or an @@ -384,7 +384,7 @@ ''' return Node(self, nodeid) - def getnodeids(self, db=None): + def getnodeids(self, retired=None): '''Retrieve all the ids of the nodes for a particular Class. ''' raise NotImplementedError @@ -438,8 +438,11 @@ WARNING: this method should never be used except in extremely rare situations where there could never be links to the node being deleted + WARNING: use retire() instead + WARNING: the properties of this node will not be available ever again + WARNING: really, use retire() instead Well, I think that's enough warnings. This method exists mostly to @@ -485,15 +488,16 @@ raise NotImplementedError def labelprop(self, default_to_id=0): - ''' Return the property name for a label for the given node. + """Return the property name for a label for the given node. This method attempts to generate a consistent label for the node. It tries the following in order: - 1. key property - 2. "name" property - 3. "title" property - 4. first property from the sorted property name list - ''' + + 1. key property + 2. "name" property + 3. "title" property + 4. first property from the sorted property name list + """ raise NotImplementedError def lookup(self, keyvalue): @@ -525,19 +529,21 @@ def filter(self, search_matches, filterspec, sort=(None,None), group=(None,None)): - ''' Return a list of the ids of the active nodes in this class that - match the 'filter' spec, sorted by the group spec and then the - sort spec. + """Return a list of the ids of the active nodes in this class that + match the 'filter' spec, sorted by the group spec and then the + sort spec. + + "filterspec" is {propname: value(s)} - "filterspec" is {propname: value(s)} - "sort" and "group" are (dir, prop) where dir is '+', '-' or None - and prop is a prop name or None - "search_matches" is {nodeid: marker} + "sort" and "group" are (dir, prop) where dir is '+', '-' or None + and prop is a prop name or None + + "search_matches" is {nodeid: marker} - The filter must match all properties specificed - but if the - property value to match is a list, any one of the values in the - list may match for that property to match. - ''' + The filter must match all properties specificed - but if the + property value to match is a list, any one of the values in the + list may match for that property to match. + """ raise NotImplementedError def count(self):
--- a/roundup/i18n.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/i18n.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,12 +15,12 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: i18n.py,v 1.3 2002-09-10 00:18:20 richard Exp $ +# $Id: i18n.py,v 1.4 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ +""" RoundUp Internationalization (I18N) -To use this module, the following code should be used: +To use this module, the following code should be used:: from roundup.i18n import _ ... @@ -28,14 +28,14 @@ Note that to enable re-ordering of inserted texts in formatting strings (which can easily happen if a sentence has to be re-ordered due to -grammatical changes), translatable formats should use named format specs: +grammatical changes), translatable formats should use named format specs:: ... _('Index of %(classname)s') % {'classname': cn} ... Also, this eases the job of translators since they have some context what the dynamic portion of a message really means. - """ +__docformat__ = 'restructuredtext' # first, we try to import gettext; this probably never fails, but we make # sure we survive this anyway
--- a/roundup/indexer.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/indexer.py Wed Feb 11 23:55:10 2004 +0000 @@ -14,24 +14,27 @@ # that promote freedom, but obviously am giving up any rights # to compel such. # -#$Id: indexer.py,v 1.17 2004-01-20 03:58:38 richard Exp $ -''' -This module provides an indexer class, RoundupIndexer, that stores text +#$Id: indexer.py,v 1.18 2004-02-11 23:55:08 richard Exp $ +'''This module provides an indexer class, RoundupIndexer, that stores text indices in a roundup instance. This class makes searching the content of messages, string properties and text files possible. ''' +__docformat__ = 'restructuredtext' + import os, shutil, re, mimetypes, marshal, zlib, errno from hyperdb import Link, Multilink class Indexer: - ''' Indexes information from roundup's hyperdb to allow efficient - searching. + '''Indexes information from roundup's hyperdb to allow efficient + searching. - Three structures are created by the indexer: + Three structures are created by the indexer:: + files {identifier: (fileid, wordcount)} words {word: {fileid: count}} fileids {fileid: identifier} - where identifier is (classname, nodeid, propertyname) + + where identifier is (classname, nodeid, propertyname) ''' def __init__(self, db_path): self.indexdb_path = os.path.join(db_path, 'indexes') @@ -69,8 +72,8 @@ return self.reindex def add_text(self, identifier, text, mime_type='text/plain'): - ''' Add some text associated with the (classname, nodeid, property) - identifier. + '''Add some text associated with the (classname, nodeid, property) + identifier. ''' # make sure the index is loaded self.load_index() @@ -114,7 +117,7 @@ self.changed = 1 def splitter(self, text, ftype): - ''' Split the contents of a text string into a list of 'words' + '''Split the contents of a text string into a list of 'words' ''' if ftype == 'text/plain': words = self.text_splitter(text) @@ -136,10 +139,10 @@ def search(self, search_terms, klass, ignore={}, dre=re.compile(r'([^\d]+)(\d+)')): - ''' Display search results looking for [search, terms] associated - with the hyperdb Class "klass". Ignore hits on {class: property}. + '''Display search results looking for [search, terms] associated + with the hyperdb Class "klass". Ignore hits on {class: property}. - "dre" is a helper, not an argument. + "dre" is a helper, not an argument. ''' # do the index lookup hits = self.find(search_terms) @@ -201,7 +204,7 @@ # we override this to ignore not 2 < word < 25 and also to fix a bug - # the (fail) case. def find(self, wordlist): - ''' Locate files that match ALL the words in wordlist + '''Locate files that match ALL the words in wordlist ''' if not hasattr(self, 'words'): self.load_index() @@ -315,7 +318,7 @@ self.changed = 0 def purge_entry(self, identifier): - ''' Remove a file from file index and word index + '''Remove a file from file index and word index ''' self.load_index()
--- a/roundup/init.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/init.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: init.py,v 1.28 2003-11-13 04:12:10 richard Exp $ +# $Id: init.py,v 1.29 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ -Init (create) a roundup instance. +"""Init (create) a roundup instance. """ +__docformat__ = 'restructuredtext' import os, sys, errno, rfc822 @@ -57,31 +57,32 @@ def install(instance_home, template): '''Install an instance using the named template and backend. - instance_home - the directory to place the instance data in - template - the directory holding the template to use in creating - the instance data + 'instance_home' + the directory to place the instance data in + 'template' + the directory holding the template to use in creating the instance data The instance_home directory will be created using the files found in the named template (roundup.templates.<name>). A standard instance_home contains: - . config.py - - simple configuration of things like the email address for the - mail gateway, the mail domain, the mail host, ... - . dbinit.py and select_db.py - - defines the schema for the hyperdatabase and indicates which - backend to use. - . interfaces.py - - defines the CGI Client and mail gateway MailGW classes that are - used by roundup.cgi, roundup-server and roundup-mailgw. - . __init__.py - - ties together all the instance information into one interface - . db/ - - the actual database that stores the instance's data - . html/ - - the html templates that are used by the CGI Client - . detectors/ - - the auditor and reactor modules for this instance + config.py + simple configuration of things like the email address for the + mail gateway, the mail domain, the mail host, ... + dbinit.py and select_db.py + defines the schema for the hyperdatabase and indicates which + backend to use. + interfaces.py + defines the CGI Client and mail gateway MailGW classes that are + used by roundup.cgi, roundup-server and roundup-mailgw. + __init__.py + ties together all the instance information into one interface + db/ + the actual database that stores the instance's data + html/ + the html templates that are used by the CGI Client + detectors/ + the auditor and reactor modules for this instance ''' # At the moment, it's just a copy copytree(template, instance_home)
--- a/roundup/install_util.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/install_util.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: install_util.py,v 1.9 2003-11-11 22:37:25 richard Exp $ +# $Id: install_util.py,v 1.10 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ -Support module to generate and check fingerprints of installed files. +"""Support module to generate and check fingerprints of installed files. """ +__docformat__ = 'restructuredtext' import os, sha, shutil
--- a/roundup/instance.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/instance.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,13 +15,13 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: instance.py,v 1.11 2003-12-06 02:46:34 richard Exp $ +# $Id: instance.py,v 1.12 2004-02-11 23:55:08 richard Exp $ -__doc__ = ''' -Tracker handling (open tracker). +'''Tracker handling (open tracker). Backwards compatibility for the old-style "imported" trackers. ''' +__docformat__ = 'restructuredtext' import os
--- a/roundup/mailer.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/mailer.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,5 +1,7 @@ -"""Sending Roundup-specific mail over SMTP.""" -# $Id: mailer.py,v 1.4 2004-01-20 00:05:46 richard Exp $ +"""Sending Roundup-specific mail over SMTP. +""" +__docformat__ = 'restructuredtext' +# $Id: mailer.py,v 1.5 2004-02-11 23:55:08 richard Exp $ import time, quopri, os, socket, smtplib, re
--- a/roundup/mailgw.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/mailgw.py Wed Feb 11 23:55:10 2004 +0000 @@ -16,8 +16,7 @@ # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -""" -An e-mail gateway for Roundup. +"""An e-mail gateway for Roundup. Incoming messages are examined for multiple parts: . In a multipart/mixed message or part, each subpart is extracted and @@ -73,8 +72,9 @@ an exception, the original message is bounced back to the sender with the explanatory message given in the exception. -$Id: mailgw.py,v 1.142 2004-01-20 00:06:09 richard Exp $ +$Id: mailgw.py,v 1.143 2004-02-11 23:55:08 richard Exp $ """ +__docformat__ = 'restructuredtext' import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri import time, random, sys
--- a/roundup/password.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/password.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: password.py,v 1.10 2003-11-11 00:35:13 richard Exp $ +# $Id: password.py,v 1.11 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ -Password handling (encoding, decoding). +"""Password handling (encoding, decoding). """ +__docformat__ = 'restructuredtext' import sha, re, string, random try:
--- a/roundup/rcsv.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/rcsv.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,8 +1,7 @@ -""" -Supplies a Python-2.3 Object Craft csv module work-alike to the extent +"""Supplies a Python-2.3 Object Craft csv module work-alike to the extent needed by Roundup using the Python 2.3 csv module. - """ +__docformat__ = 'restructuredtext' from roundup.i18n import _ from cStringIO import StringIO
--- a/roundup/rfc2822.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/rfc2822.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,3 +1,7 @@ +"""Some rfc822 functions taken from the new (python2.3) "email" module. +""" +__docformat__ = 'restructuredtext' + import re from string import letters, digits from binascii import b2a_base64, a2b_base64 @@ -37,7 +41,8 @@ return dec def unquote_match(match): - """Turn a match in the form =AB to the ASCII character with value 0xab + """Turn a match in the form ``=AB`` to the ASCII character with value + 0xab. Taken from 'email' module """ @@ -45,7 +50,7 @@ return chr(int(s[1:3], 16)) def qp_decode(s): - """Decode a string encoded with RFC 2045 MIME header `Q' encoding. + """Decode a string encoded with RFC 2045 MIME header 'Q' encoding. This function does not parse a full MIME header value encoded with quoted-printable (like =?iso-8895-1?q?Hello_World?=) -- please use
--- a/roundup/roundupdb.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/roundupdb.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,11 +15,12 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundupdb.py,v 1.96 2003-12-05 04:43:30 richard Exp $ +# $Id: roundupdb.py,v 1.97 2004-02-11 23:55:08 richard Exp $ -__doc__ = """ -Extending hyperdb with types specific to issue-tracking. +"""Extending hyperdb with types specific to issue-tracking. """ +__docformat__ = 'restructuredtext' + from __future__ import nested_scopes import re, os, smtplib, socket, time, random @@ -95,15 +96,16 @@ # deviation from spec - was called IssueClass class IssueClass: - """ This class is intended to be mixed-in with a hyperdb backend - implementation. The backend should provide a mechanism that - enforces the title, messages, files, nosy and superseder - properties: - properties['title'] = hyperdb.String(indexme='yes') - properties['messages'] = hyperdb.Multilink("msg") - properties['files'] = hyperdb.Multilink("file") - properties['nosy'] = hyperdb.Multilink("user") - properties['superseder'] = hyperdb.Multilink(classname) + """This class is intended to be mixed-in with a hyperdb backend + implementation. The backend should provide a mechanism that + enforces the title, messages, files, nosy and superseder + properties: + + - title = hyperdb.String(indexme='yes') + - messages = hyperdb.Multilink("msg") + - files = hyperdb.Multilink("file") + - nosy = hyperdb.Multilink("user") + - superseder = hyperdb.Multilink(classname) """ # New methods:
--- a/roundup/scripts/__init__.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/scripts/__init__.py Wed Feb 11 23:55:10 2004 +0000 @@ -15,10 +15,12 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: __init__.py,v 1.2 2002-09-10 01:07:05 richard Exp $ +# $Id: __init__.py,v 1.3 2004-02-11 23:55:10 richard Exp $ -__doc__ = ''' -Subpackage containing the modules that implement the command line tools. +'''Subpackage containing the modules that implement the command +line tools. + Note that these are imported by script stubs generated by "setup.py". ''' +__docformat__ = 'restructuredtext' # vim: set filetype=python ts=4 sw=4 et si
--- a/roundup/scripts/roundup_admin.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/scripts/roundup_admin.py Wed Feb 11 23:55:10 2004 +0000 @@ -14,7 +14,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundup_admin.py,v 1.5 2003-04-24 04:27:32 richard Exp $ +# $Id: roundup_admin.py,v 1.6 2004-02-11 23:55:10 richard Exp $ + +"""Command-line script stub that calls the roundup.admin functions. +""" +__docformat__ = 'restructuredtext' # python version check from roundup import version_check
--- a/roundup/scripts/roundup_mailgw.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/scripts/roundup_mailgw.py Wed Feb 11 23:55:10 2004 +0000 @@ -14,7 +14,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: roundup_mailgw.py,v 1.10 2003-04-24 04:27:32 richard Exp $ +# $Id: roundup_mailgw.py,v 1.11 2004-02-11 23:55:10 richard Exp $ + +"""Command-line script stub that calls the roundup.mailgw. +""" +__docformat__ = 'restructuredtext' # python version check from roundup import version_check
--- a/roundup/scripts/roundup_server.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/scripts/roundup_server.py Wed Feb 11 23:55:10 2004 +0000 @@ -14,10 +14,12 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -""" HTTP Server that serves roundup. + +"""Command-line script that runs a server over roundup.cgi.client. -$Id: roundup_server.py,v 1.36 2003-12-06 02:46:34 richard Exp $ +$Id: roundup_server.py,v 1.37 2004-02-11 23:55:10 richard Exp $ """ +__docformat__ = 'restructuredtext' # python version check from roundup import version_check
--- a/roundup/security.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/security.py Wed Feb 11 23:55:10 2004 +0000 @@ -1,3 +1,7 @@ +"""Handle the security declarations used in Roundup trackers. +""" +__docformat__ = 'restructuredtext' + import weakref from roundup import hyperdb
--- a/roundup/token.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/token.py Wed Feb 11 23:55:10 2004 +0000 @@ -8,23 +8,25 @@ # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # -# $Id: token.py,v 1.3 2002-09-10 00:18:20 richard Exp $ +# $Id: token.py,v 1.4 2004-02-11 23:55:08 richard Exp $ # -__doc__ = """ -This module provides the tokeniser used by roundup-admin. +"""This module provides the tokeniser used by roundup-admin. """ +__docformat__ = 'restructuredtext' def token_split(s, whitespace=' \r\n\t', quotes='\'"', escaped={'r':'\r', 'n':'\n', 't':'\t'}): - '''Split the string up into tokens. An occurence of a ' or " in the - input will cause the splitter to ignore whitespace until a matching - quote char is found. Embedded non-matching quote chars are also - skipped. - Whitespace and quoting characters may be escaped using a backslash. - \r, \n and \t are converted to carriage-return, newline and tab. - All other backslashed characters are left as-is. - Valid: + '''Split the string up into tokens. An occurence of a ``'`` or ``"`` in + the input will cause the splitter to ignore whitespace until a matching + quote char is found. Embedded non-matching quote chars are also skipped. + + Whitespace and quoting characters may be escaped using a backslash. + ``\r``, ``\n`` and ``\t`` are converted to carriage-return, newline and + tab. All other backslashed characters are left as-is. + + Valid examples:: + hello world (2 tokens: hello, world) "hello world" (1 token: hello world) "Roch'e" Compaan (2 tokens: Roch'e Compaan) @@ -33,7 +35,9 @@ \\ (1 token: \) \n (1 token: a newline) \o (1 token: \o) - Invalid: + + Invalid examples:: + "hello world (no matching quote) Roch'e Compaan (no matching quote) '''
--- a/roundup/version_check.py Wed Feb 11 21:34:31 2004 +0000 +++ b/roundup/version_check.py Wed Feb 11 23:55:10 2004 +0000 @@ -16,7 +16,11 @@ # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. # -# $Id: version_check.py,v 1.3 2002-09-10 00:18:20 richard Exp $ +# $Id: version_check.py,v 1.4 2004-02-11 23:55:08 richard Exp $ + +"""Enforces the minimum Python version that Roundup requires. +""" +__docformat__ = 'restructuredtext' import sys if not hasattr(sys, 'version_info') or sys.version_info[:3] < (2,1,1):
