diff --git a/Doc/lib/libcsv.tex b/Doc/lib/libcsv.tex index e2877ee6ad7..bf8b0bf789c 100644 --- a/Doc/lib/libcsv.tex +++ b/Doc/lib/libcsv.tex @@ -117,14 +117,18 @@ Return the names of all registered dialects. The \module{csv} module defines the following classes: -\begin{classdesc}{DictReader}{csvfile, fieldnames\optional{, +\begin{classdesc}{DictReader}{csvfile\optional{, + fieldnames=\constant{None},\optional{, restkey=\constant{None}\optional{, restval=\constant{None}\optional{, dialect=\code{'excel'}\optional{, - fmtparam}}}}} + fmtparam}}}}}} Create an object which operates like a regular reader but maps the -information read into a dict whose keys are given by the \var{fieldnames} -parameter. If the row read has fewer fields than the fieldnames sequence, +information read into a dict whose keys are given by the optional +{} \var{fieldnames} +parameter. If the \var{fieldnames} parameter is omitted, the values in +the first row of the \var{csvfile} will be used as the fieldnames. +If the row read has fewer fields than the fieldnames sequence, the value of \var{restval} will be used as the default value. If the row read has more fields than the fieldnames sequence, the remaining data is added as a sequence keyed by the value of \var{restkey}. If the row read @@ -149,6 +153,13 @@ method contains a key not found in \var{fieldnames}, the optional to \code{'raise'} a \exception{ValueError} is raised. If it is set to \code{'ignore'}, extra values in the dictionary are ignored. All other parameters are interpreted as for \class{writer} objects. + +Note that unlike the \class{DictReader} class, the \var{fieldnames} +parameter of the \class{DictWriter} is not optional. Since Python's +\class{dict} objects are not ordered, there is not enough information +available to deduce the order in which the row should be written to the +\var{csvfile}. + \end{classdesc} \begin{classdesc*}{Dialect}{} diff --git a/Lib/csv.py b/Lib/csv.py index 096badc7bbc..f2389fd3042 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -92,7 +92,7 @@ register_dialect("excel-tab", excel_tab) class DictReader: - def __init__(self, f, fieldnames, restkey=None, restval=None, + def __init__(self, f, fieldnames=None, restkey=None, restval=None, dialect="excel", *args, **kwds): self.fieldnames = fieldnames # list of keys for the dict self.restkey = restkey # key to catch long rows @@ -104,6 +104,10 @@ class DictReader: def next(self): row = self.reader.next() + if self.fieldnames is None: + self.fieldnames = row + 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 diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index d85c5b6cb39..29a13cb7a0e 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -382,7 +382,6 @@ class TestQuotedEscapedExcel(TestCsvBase): def test_read_escape_fieldsep(self): self.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']]) -# Disabled, pending support in csv.utils module class TestDictFields(unittest.TestCase): ### "long" means the row is longer than the number of fieldnames ### "short" means there are fewer elements in the row than fieldnames @@ -401,6 +400,10 @@ class TestDictFields(unittest.TestCase): fieldnames=["f1", "f2", "f3"]) self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'}) + def test_read_dict_no_fieldnames(self): + reader = csv.DictReader(StringIO("f1,f2,f3\r\n1,2,abc\r\n")) + self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'}) + def test_read_long(self): reader = csv.DictReader(StringIO("1,2,abc,4,5,6\r\n"), fieldnames=["f1", "f2"]) @@ -413,6 +416,12 @@ class TestDictFields(unittest.TestCase): self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "_rest": ["abc", "4", "5", "6"]}) + def test_read_long_with_rest_no_fieldnames(self): + reader = csv.DictReader(StringIO("f1,f2\r\n1,2,abc,4,5,6\r\n"), + restkey="_rest") + self.assertEqual(reader.next(), {"f1": '1', "f2": '2', + "_rest": ["abc", "4", "5", "6"]}) + def test_read_short(self): reader = csv.DictReader(["1,2,abc,4,5,6\r\n","1,2,abc\r\n"], fieldnames="1 2 3 4 5 6".split(),