Code

python2.3 CSV support, also missing thankyou in index.txt :)
authorrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 28 Aug 2003 04:46:54 +0000 (04:46 +0000)
committerrichard <richard@57a73879-2fb5-44c3-a270-3262357dd7e2>
Thu, 28 Aug 2003 04:46:54 +0000 (04:46 +0000)
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1834 57a73879-2fb5-44c3-a270-3262357dd7e2

CHANGES.txt
doc/index.txt
roundup/admin.py
roundup/cgi/client.py
roundup/cgi/templating.py
roundup/rcsv.py [new file with mode: 0644]

index b4346010f1293b3ca9c5013778bdfa641f712340..ca4cadcd3cfed33273d0076d36b8ec30dd7f8834 100644 (file)
@@ -10,6 +10,7 @@ Fixed:
 - 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 (thanks Paul Dubois for the patch)
 
 
 2003-08-08 0.6.0
index 47b7e8284963a36c94b7002c20ba5e6629f0cb43..89b3c3d76e948836c6e74772e8ffe618cf09d360 100644 (file)
@@ -56,9 +56,11 @@ Duncan Booth,
 Seb Brezel,
 Titus Brown,
 Roch'e Compaan,
+Paul F. Dubois,
 Jeff Epler,
 Hernan Martinez Foffani,
 Ajit George,
+Johannes Gijsbers,
 Gus Gollings,
 Dan Grassi,
 Engelbert Gruber,
index 06fac7827c9d0cb101b4beb8a99085d7f817450f..15df68bebb32169ab4c403f751f3286e0a2d65fa 100644 (file)
 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 # 
-# $Id: admin.py,v 1.56 2003-08-26 00:06:55 richard Exp $
+# $Id: admin.py,v 1.57 2003-08-28 04:46:39 richard Exp $
 
 '''Administration commands for maintaining Roundup trackers.
 '''
 
 import sys, os, getpass, getopt, re, UserDict, shutil, rfc822
-try:
-    import csv
-except ImportError:
-    csv = None
-from roundup import date, hyperdb, roundupdb, init, password, token
+from roundup import date, hyperdb, roundupdb, init, password, token, rcsv
 from roundup import __version__ as roundup_version
 import roundup.instance
 from roundup.i18n import _
@@ -1063,15 +1059,12 @@ Command help:
         colon-separated-value files that are placed in the nominated
         destination directory. The journals are not exported.
         '''
-        # we need the CSV module
-        if csv is None:
-            raise UsageError, \
-                _('Sorry, you need the csv module to use this function.\n'
-                'Get it from: http://www.object-craft.com.au/projects/csv/')
-
         # grab the directory to export to
         if len(args) < 1:
             raise UsageError, _('Not enough arguments supplied')
+        if rcsv.error:
+            raise UsageError, _(rcsv.error)
+
         dir = args[-1]
 
         # get the list of classes to export
@@ -1080,26 +1073,24 @@ Command help:
         else:
             classes = self.db.classes.keys()
 
-        # use the csv parser if we can - it's faster
-        p = csv.parser(field_sep=':')
-
         # do all the classes specified
         for classname in classes:
             cl = self.get_class(classname)
             f = open(os.path.join(dir, classname+'.csv'), 'w')
+            writer = rcsv.writer(f, rcsv.colon_separated)
             properties = cl.getprops()
             propnames = properties.keys()
             propnames.sort()
-            l = propnames[:]
-            l.append('is retired')
-            print >> f, p.join(l)
+            fields = propnames[:]
+            fields.append('is retired')
+            writer.writerow(fields)
 
             # all nodes for this class (not using list() 'cos it doesn't
             # include retired nodes)
 
             for nodeid in self.db.getclass(classname).getnodeids():
                 # get the regular props
-                print >>f, p.join(cl.export_list(propnames, nodeid))
+                writer.writerow (cl.export_list(propnames, nodeid))
 
             # close this file
             f.close()
@@ -1122,11 +1113,8 @@ Command help:
         '''
         if len(args) < 1:
             raise UsageError, _('Not enough arguments supplied')
-        if csv is None:
-            raise UsageError, \
-                _('Sorry, you need the csv module to use this function.\n'
-                'Get it from: http://www.object-craft.com.au/projects/csv/')
-
+        if rcsv.error:
+            raise UsageError, _(rcsv.error)
         from roundup import hyperdb
 
         for file in os.listdir(args[0]):
@@ -1141,26 +1129,20 @@ Command help:
 
             # ensure that the properties and the CSV file headings match
             cl = self.get_class(classname)
-            p = csv.parser(field_sep=':')
-            file_props = p.parse(f.readline())
+            reader = rcsv.reader(f, rcsv.colon_separated)
+            file_props = None
+            maxid = 1
 
             # loop through the file and create a node for each entry
-            maxid = 1
-            while 1:
-                line = f.readline()
-                if not line: break
-
-                # parse lines until we get a complete entry
-                while 1:
-                    l = p.parse(line)
-                    if l: break
-                    line = f.readline()
-                    if not line:
-                        raise ValueError, "Unexpected EOF during CSV parse"
+            for r in reader:
+                if file_props is None:
+                    file_props = r
+                    continue
 
                 # do the import and figure the current highest nodeid
-                maxid = max(maxid, int(cl.import_list(file_props, l)))
+                maxid = max(maxid, int(cl.import_list(file_props, r)))
 
+            # set the id counter
             print 'setting', classname, maxid+1
             self.db.setid(classname, str(maxid+1))
         return 0
index c2ccb937fe1a579b8cad312bdbfc9b3c7a0447fd..6dce8d5b2682c0f1dbfd9d768dcf0c3d508bc1d0 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: client.py,v 1.131 2003-08-28 01:39:15 richard Exp $
+# $Id: client.py,v 1.132 2003-08-28 04:46:39 richard Exp $
 
 __doc__ = """
 WWW request handler (also used in the stand-alone server).
@@ -8,7 +8,7 @@ import os, os.path, cgi, StringIO, urlparse, re, traceback, mimetypes, urllib
 import binascii, Cookie, time, random, MimeWriter, smtplib, socket, quopri
 import stat, rfc822, string
 
-from roundup import roundupdb, date, hyperdb, password, token
+from roundup import roundupdb, date, hyperdb, password, token, rcsv
 from roundup.i18n import _
 from roundup.cgi.templating import Templates, HTMLRequest, NoTemplate
 from roundup.cgi import cgitb
@@ -1219,12 +1219,8 @@ You should then receive another email with the new password.
                 _('You do not have permission to edit %s' %self.classname))
 
         # get the CSV module
-        try:
-            import csv
-        except ImportError:
-            self.error_message.append(_(
-                'Sorry, you need the csv module to use this function.<br>\n'
-                'Get it from: <a href="http://www.object-craft.com.au/projects/csv/">http://www.object-craft.com.au/projects/csv/'))
+        if rcsv.error:
+            self.error_message.append(_(rcsv.error))
             return
 
         cl = self.db.classes[self.classname]
@@ -1233,16 +1229,13 @@ You should then receive another email with the new password.
         props = ['id'] + idlessprops
 
         # do the edit
-        rows = self.form['rows'].value.splitlines()
-        p = csv.parser()
+        rows = StringIO.StringIO(self.form['rows'].value)
+        reader = rcsv.reader(rows, rcsv.comma_separated)
         found = {}
         line = 0
-        for row in rows[1:]:
+        for values in reader:
             line += 1
-            values = p.parse(row)
-            # not a complete row, keep going
-            if not values: continue
-
+            if line == 1: continue
             # skip property names header
             if values == props:
                 continue
index 7a14ffbedd68e19026b48fa7922e4327047b9440..7008d9eec2b1d260e66f6d6df1832e8d36c4873b 100644 (file)
@@ -1,6 +1,6 @@
 import sys, cgi, urllib, os, re, os.path, time, errno
 
-from roundup import hyperdb, date
+from roundup import hyperdb, date, rcsv
 from roundup.i18n import _
 
 try:
@@ -395,17 +395,13 @@ class HTMLClass(HTMLPermissions):
     def csv(self):
         ''' Return the items of this class as a chunk of CSV text.
         '''
-        # get the CSV module
-        try:
-            import csv
-        except ImportError:
-            return 'Sorry, you need the csv module to use this function.\n'\
-                'Get it from: http://www.object-craft.com.au/projects/csv/'
+        if rcsv.error:
+            return rcsv.error
 
         props = self.propnames()
-        p = csv.parser()
         s = StringIO.StringIO()
-        s.write(p.join(props) + '\n')
+        writer = rcsv.writer(s, rcsv.comma_separated)
+        writer.writerow(props)
         for nodeid in self._klass.list():
             l = []
             for name in props:
@@ -416,7 +412,7 @@ class HTMLClass(HTMLPermissions):
                     l.append(':'.join(map(str, value)))
                 else:
                     l.append(str(self._klass.get(nodeid, name)))
-            s.write(p.join(l) + '\n')
+            writer.writerow(l)
         return s.getvalue()
 
     def propnames(self):
diff --git a/roundup/rcsv.py b/roundup/rcsv.py
new file mode 100644 (file)
index 0000000..da6a0a6
--- /dev/null
@@ -0,0 +1,78 @@
+"""
+Supplies a Python-2.3 Object Craft csv module work-alike to the extent
+needed by Roundup using the Python 2.3 csv module.
+
+"""
+
+from roundup.i18n import _
+error = """Sorry, you need a module compatible with the csv module.
+Either upgrade your Python to 2.3 or later, or get and install
+the csv module from:
+http://www.object-craft.com.au/projects/csv/
+
+These two csv modules are different but Roundup can use either.
+"""
+try:
+    import csv
+    try:
+        reader = csv.reader
+        writer = csv.writer
+        excel = csv.excel
+        error = ''
+    except AttributeError:
+        # fake it all up using the Object-Craft CSV module
+        class excel:
+            pass
+        if hasattr(csv, 'parser'):
+            error = ''
+            def reader(fileobj, dialect=excel):
+                # note real readers take an iterable but 2.1 doesn't
+                # support iterable access to file objects.
+                result = []
+                p = csv.parser(field_sep=dialect.delimiter)
+
+                while 1:
+                    line = fileobj.readline()
+                    if not line: break
+                    # parse lines until we get a complete entry
+                    while 1:
+                        fields = p.parse(line)
+                        if fields: break
+                        line = fileobj.readline()
+                        if not line:
+                            raise ValueError, "Unexpected EOF during CSV parse"
+                    result.append(fields)
+                return result
+            class writer:
+                def __init__(self, fileobj, dialect=excel):
+                    self.fileobj = fileobj
+                    self.p = csv.parser(field_sep = dialect.delimiter)
+                def writerow(self, fields):
+                    print >>self.fileobj, self.p.join(fields)
+                def writerows(self, rows):
+                    for fields in rows:
+                        print >>self.fileobj, self.p.join(fields)
+
+except ImportError:
+    class excel:
+        pass
+       
+class colon_separated(excel):
+    delimiter = ':' 
+class comma_separated(excel):
+    delimiter = ',' 
+
+
+if __name__ == "__main__":
+    f=open('testme.txt', 'r')
+    r = reader(f, colon_separated)
+    remember = []
+    for record in r:
+        print record
+        remember.append(record)
+    f.close()
+    import sys
+    w = writer(sys.stdout, colon_separated)
+    w.writerows(remember)
+