From: richard Date: Thu, 28 Aug 2003 04:46:54 +0000 (+0000) Subject: python2.3 CSV support, also missing thankyou in index.txt :) X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=76184ec46d422c1f39349a1e1a7983ba4887a918;p=roundup.git python2.3 CSV support, also missing thankyou in index.txt :) git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1834 57a73879-2fb5-44c3-a270-3262357dd7e2 --- diff --git a/CHANGES.txt b/CHANGES.txt index b434601..ca4cadc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -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 diff --git a/doc/index.txt b/doc/index.txt index 47b7e82..89b3c3d 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -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, diff --git a/roundup/admin.py b/roundup/admin.py index 06fac78..15df68b 100644 --- a/roundup/admin.py +++ b/roundup/admin.py @@ -16,17 +16,13 @@ # 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 diff --git a/roundup/cgi/client.py b/roundup/cgi/client.py index c2ccb93..6dce8d5 100644 --- a/roundup/cgi/client.py +++ b/roundup/cgi/client.py @@ -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.
\n' - 'Get it from: 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 diff --git a/roundup/cgi/templating.py b/roundup/cgi/templating.py index 7a14ffb..7008d9e 100644 --- a/roundup/cgi/templating.py +++ b/roundup/cgi/templating.py @@ -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 index 0000000..da6a0a6 --- /dev/null +++ b/roundup/rcsv.py @@ -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) +