new CSV file processing module - see PEP 305
diff --git a/Lib/csv/csv.py b/Lib/csv/csv.py
new file mode 100644
index 0000000..a3ea4e2
--- /dev/null
+++ b/Lib/csv/csv.py
@@ -0,0 +1,138 @@
+from _csv import Error, __version__, writer, reader, register_dialect, \
+ unregister_dialect, get_dialect, list_dialects, \
+ QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \
+ __doc__
+
+__all__ = [ "QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
+ "Error", "Dialect", "excel", "excel_tab", "reader", "writer",
+ "register_dialect", "get_dialect", "list_dialects",
+ "unregister_dialect", "__version__", "DictReader", "DictWriter" ]
+
+class Dialect:
+ _name = ""
+ _valid = False
+ # placeholders
+ delimiter = None
+ quotechar = None
+ escapechar = None
+ doublequote = None
+ skipinitialspace = None
+ lineterminator = None
+ quoting = None
+
+ def __init__(self):
+ if self.__class__ != Dialect:
+ self._valid = True
+ errors = self._validate()
+ if errors != []:
+ raise Error, "Dialect did not validate: %s" % ", ".join(errors)
+
+ def _validate(self):
+ errors = []
+ if not self._valid:
+ errors.append("can't directly instantiate Dialect class")
+
+ if self.delimiter is None:
+ errors.append("delimiter character not set")
+ elif (not isinstance(self.delimiter, str) or
+ len(self.delimiter) > 1):
+ errors.append("delimiter must be one-character string")
+
+ if self.quotechar is None:
+ if self.quoting != QUOTE_NONE:
+ errors.append("quotechar not set")
+ elif (not isinstance(self.quotechar, str) or
+ len(self.quotechar) > 1):
+ errors.append("quotechar must be one-character string")
+
+ if self.lineterminator is None:
+ errors.append("lineterminator not set")
+ elif not isinstance(self.lineterminator, str):
+ errors.append("lineterminator must be a string")
+
+ if self.doublequote not in (True, False):
+ errors.append("doublequote parameter must be True or False")
+
+ if self.skipinitialspace not in (True, False):
+ errors.append("skipinitialspace parameter must be True or False")
+
+ if self.quoting is None:
+ errors.append("quoting parameter not set")
+
+ if self.quoting is QUOTE_NONE:
+ if (not isinstance(self.escapechar, (unicode, str)) or
+ len(self.escapechar) > 1):
+ errors.append("escapechar must be a one-character string or unicode object")
+
+ return errors
+
+class excel(Dialect):
+ delimiter = ','
+ quotechar = '"'
+ doublequote = True
+ skipinitialspace = False
+ lineterminator = '\r\n'
+ quoting = QUOTE_MINIMAL
+register_dialect("excel", excel)
+
+class excel_tab(excel):
+ delimiter = '\t'
+register_dialect("excel-tab", excel_tab)
+
+
+class DictReader:
+ def __init__(self, f, fieldnames, restkey=None, restval=None,
+ dialect="excel", *args):
+ self.fieldnames = fieldnames # list of keys for the dict
+ self.restkey = restkey # key to catch long rows
+ self.restval = restval # default value for short rows
+ self.reader = reader(f, dialect, *args)
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ row = self.reader.next()
+ # unlike the basic reader, we prefer not to return blanks,
+ # because we will typically wind up with a dict full of None
+ # values
+ while row == []:
+ row = self.reader.next()
+ d = dict(zip(self.fieldnames, row))
+ lf = len(self.fieldnames)
+ lr = len(row)
+ if lf < lr:
+ d[self.restkey] = row[lf:]
+ elif lf > lr:
+ for key in self.fieldnames[lr:]:
+ d[key] = self.restval
+ return d
+
+
+class DictWriter:
+ def __init__(self, f, fieldnames, restval="", extrasaction="raise",
+ dialect="excel", *args):
+ self.fieldnames = fieldnames # list of keys for the dict
+ self.restval = restval # for writing short dicts
+ if extrasaction.lower() not in ("raise", "ignore"):
+ raise ValueError, \
+ ("extrasaction (%s) must be 'raise' or 'ignore'" %
+ extrasaction)
+ self.extrasaction = extrasaction
+ self.writer = writer(f, dialect, *args)
+
+ def _dict_to_list(self, rowdict):
+ if self.extrasaction == "raise":
+ for k in rowdict.keys():
+ if k not in self.fieldnames:
+ raise ValueError, "dict contains fields not in fieldnames"
+ return [rowdict.get(key, self.restval) for key in self.fieldnames]
+
+ def writerow(self, rowdict):
+ return self.writer.writerow(self._dict_to_list(rowdict))
+
+ def writerows(self, rowdicts):
+ rows = []
+ for rowdict in rowdicts:
+ rows.append(self._dict_to_list(rowdict))
+ return self.writer.writerows(rows)