Make the fieldnames argument optional in the DictReader. If self.fieldnames
is None, the next row read is used as the fieldnames. In the common case, this means the programmer doesn't need to know the fieldnames ahead of time. The first row of the file will be used. In the uncommon case, this means the programmer can set the reader's fieldnames attribute to None at any time and have the next row read as the next set of fieldnames, so a csv file can contain several "sections", each with different fieldnames.
This commit is contained in:
parent
3bbd6543a0
commit
dffeed3ffa
|
@ -117,14 +117,18 @@ Return the names of all registered dialects.
|
||||||
|
|
||||||
The \module{csv} module defines the following classes:
|
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{,
|
restkey=\constant{None}\optional{,
|
||||||
restval=\constant{None}\optional{,
|
restval=\constant{None}\optional{,
|
||||||
dialect=\code{'excel'}\optional{,
|
dialect=\code{'excel'}\optional{,
|
||||||
fmtparam}}}}}
|
fmtparam}}}}}}
|
||||||
Create an object which operates like a regular reader but maps the
|
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}
|
information read into a dict whose keys are given by the optional
|
||||||
parameter. If the row read has fewer fields than the fieldnames sequence,
|
{} \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
|
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
|
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
|
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
|
to \code{'raise'} a \exception{ValueError} is raised. If it is set to
|
||||||
\code{'ignore'}, extra values in the dictionary are ignored. All other
|
\code{'ignore'}, extra values in the dictionary are ignored. All other
|
||||||
parameters are interpreted as for \class{writer} objects.
|
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}
|
\end{classdesc}
|
||||||
|
|
||||||
\begin{classdesc*}{Dialect}{}
|
\begin{classdesc*}{Dialect}{}
|
||||||
|
|
|
@ -92,7 +92,7 @@ register_dialect("excel-tab", excel_tab)
|
||||||
|
|
||||||
|
|
||||||
class DictReader:
|
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):
|
dialect="excel", *args, **kwds):
|
||||||
self.fieldnames = fieldnames # list of keys for the dict
|
self.fieldnames = fieldnames # list of keys for the dict
|
||||||
self.restkey = restkey # key to catch long rows
|
self.restkey = restkey # key to catch long rows
|
||||||
|
@ -104,6 +104,10 @@ class DictReader:
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
row = self.reader.next()
|
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,
|
# unlike the basic reader, we prefer not to return blanks,
|
||||||
# because we will typically wind up with a dict full of None
|
# because we will typically wind up with a dict full of None
|
||||||
# values
|
# values
|
||||||
|
|
|
@ -382,7 +382,6 @@ class TestQuotedEscapedExcel(TestCsvBase):
|
||||||
def test_read_escape_fieldsep(self):
|
def test_read_escape_fieldsep(self):
|
||||||
self.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']])
|
self.readerAssertEqual('"abc\\,def"\r\n', [['abc,def']])
|
||||||
|
|
||||||
# Disabled, pending support in csv.utils module
|
|
||||||
class TestDictFields(unittest.TestCase):
|
class TestDictFields(unittest.TestCase):
|
||||||
### "long" means the row is longer than the number of fieldnames
|
### "long" means the row is longer than the number of fieldnames
|
||||||
### "short" means there are fewer elements in the row than fieldnames
|
### "short" means there are fewer elements in the row than fieldnames
|
||||||
|
@ -401,6 +400,10 @@ class TestDictFields(unittest.TestCase):
|
||||||
fieldnames=["f1", "f2", "f3"])
|
fieldnames=["f1", "f2", "f3"])
|
||||||
self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
|
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):
|
def test_read_long(self):
|
||||||
reader = csv.DictReader(StringIO("1,2,abc,4,5,6\r\n"),
|
reader = csv.DictReader(StringIO("1,2,abc,4,5,6\r\n"),
|
||||||
fieldnames=["f1", "f2"])
|
fieldnames=["f1", "f2"])
|
||||||
|
@ -413,6 +416,12 @@ class TestDictFields(unittest.TestCase):
|
||||||
self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
|
self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
|
||||||
"_rest": ["abc", "4", "5", "6"]})
|
"_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):
|
def test_read_short(self):
|
||||||
reader = csv.DictReader(["1,2,abc,4,5,6\r\n","1,2,abc\r\n"],
|
reader = csv.DictReader(["1,2,abc,4,5,6\r\n","1,2,abc\r\n"],
|
||||||
fieldnames="1 2 3 4 5 6".split(),
|
fieldnames="1 2 3 4 5 6".split(),
|
||||||
|
|
Loading…
Reference in New Issue