accept issue 3436
This commit is contained in:
parent
b04d4853a7
commit
a032bf41f6
|
@ -382,6 +382,18 @@ Reader objects have the following public attributes:
|
|||
.. versionadded:: 2.5
|
||||
|
||||
|
||||
DictReader objects have the following public attribute:
|
||||
|
||||
|
||||
.. attribute:: csvreader.fieldnames
|
||||
|
||||
If not passed as a parameter when creating the object, this attribute is
|
||||
initialized upon first access or when the first record is read from the
|
||||
file.
|
||||
|
||||
.. versionchanged:: 2.6
|
||||
|
||||
|
||||
Writer Objects
|
||||
--------------
|
||||
|
||||
|
|
22
Lib/csv.py
22
Lib/csv.py
|
@ -71,7 +71,7 @@ register_dialect("excel-tab", excel_tab)
|
|||
class DictReader:
|
||||
def __init__(self, f, fieldnames=None, restkey=None, restval=None,
|
||||
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.restval = restval # default value for short rows
|
||||
self.reader = reader(f, dialect, *args, **kwds)
|
||||
|
@ -81,11 +81,25 @@ class DictReader:
|
|||
def __iter__(self):
|
||||
return self
|
||||
|
||||
@property
|
||||
def fieldnames(self):
|
||||
if self._fieldnames is None:
|
||||
try:
|
||||
self._fieldnames = self.reader.next()
|
||||
except StopIteration:
|
||||
pass
|
||||
self.line_num = self.reader.line_num
|
||||
return self._fieldnames
|
||||
|
||||
@fieldnames.setter
|
||||
def fieldnames(self, value):
|
||||
self._fieldnames = value
|
||||
|
||||
def next(self):
|
||||
if self.line_num == 0:
|
||||
# Used only for its side effect.
|
||||
self.fieldnames
|
||||
row = self.reader.next()
|
||||
if self.fieldnames is None:
|
||||
self.fieldnames = row
|
||||
row = self.reader.next()
|
||||
self.line_num = self.reader.line_num
|
||||
|
||||
# unlike the basic reader, we prefer not to return blanks,
|
||||
|
|
|
@ -611,11 +611,43 @@ class TestDictFields(unittest.TestCase):
|
|||
fileobj.write("f1,f2,f3\r\n1,2,abc\r\n")
|
||||
fileobj.seek(0)
|
||||
reader = csv.DictReader(fileobj)
|
||||
self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
|
||||
self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
|
||||
finally:
|
||||
fileobj.close()
|
||||
os.unlink(name)
|
||||
|
||||
# Two test cases to make sure existing ways of implicitly setting
|
||||
# fieldnames continue to work. Both arise from discussion in issue3436.
|
||||
def test_read_dict_fieldnames_from_file(self):
|
||||
fd, name = tempfile.mkstemp()
|
||||
f = os.fdopen(fd, "w+b")
|
||||
try:
|
||||
f.write("f1,f2,f3\r\n1,2,abc\r\n")
|
||||
f.seek(0)
|
||||
reader = csv.DictReader(f, fieldnames=csv.reader(f).next())
|
||||
self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
|
||||
self.assertEqual(reader.next(), {"f1": '1', "f2": '2', "f3": 'abc'})
|
||||
finally:
|
||||
f.close()
|
||||
os.unlink(name)
|
||||
|
||||
def test_read_dict_fieldnames_chain(self):
|
||||
import itertools
|
||||
fd, name = tempfile.mkstemp()
|
||||
f = os.fdopen(fd, "w+b")
|
||||
try:
|
||||
f.write("f1,f2,f3\r\n1,2,abc\r\n")
|
||||
f.seek(0)
|
||||
reader = csv.DictReader(f)
|
||||
first = next(reader)
|
||||
for row in itertools.chain([first], reader):
|
||||
self.assertEqual(reader.fieldnames, ["f1", "f2", "f3"])
|
||||
self.assertEqual(row, {"f1": '1', "f2": '2', "f3": 'abc'})
|
||||
finally:
|
||||
f.close()
|
||||
os.unlink(name)
|
||||
|
||||
def test_read_long(self):
|
||||
fd, name = tempfile.mkstemp()
|
||||
fileobj = os.fdopen(fd, "w+b")
|
||||
|
@ -651,6 +683,7 @@ class TestDictFields(unittest.TestCase):
|
|||
fileobj.write("f1,f2\r\n1,2,abc,4,5,6\r\n")
|
||||
fileobj.seek(0)
|
||||
reader = csv.DictReader(fileobj, restkey="_rest")
|
||||
self.assertEqual(reader.fieldnames, ["f1", "f2"])
|
||||
self.assertEqual(reader.next(), {"f1": '1', "f2": '2',
|
||||
"_rest": ["abc", "4", "5", "6"]})
|
||||
finally:
|
||||
|
|
|
@ -41,6 +41,10 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #3436: Make csv.DictReader's fieldnames attribute a property so that
|
||||
upon first access it can be automatically initialized from the csv file if
|
||||
it wasn't initialized during instantiation.
|
||||
|
||||
- Issue #2338: Create imp.reload() to help with transitioning to Python 3.0 as
|
||||
the reload() built-in has been removed.
|
||||
|
||||
|
|
Loading…
Reference in New Issue