mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
gh-76728: Coerce DictReader and DictWriter fieldnames argument to a list (GH-32225)
This commit is contained in:
parent
c09fa7542c
commit
cd492d43a2
4 changed files with 37 additions and 0 deletions
|
@ -167,6 +167,8 @@ The :mod:`csv` module defines the following classes:
|
||||||
All other optional or keyword arguments are passed to the underlying
|
All other optional or keyword arguments are passed to the underlying
|
||||||
:class:`reader` instance.
|
:class:`reader` instance.
|
||||||
|
|
||||||
|
If the argument passed to *fieldnames* is an iterator, it will be coerced to a :class:`list`.
|
||||||
|
|
||||||
.. versionchanged:: 3.6
|
.. versionchanged:: 3.6
|
||||||
Returned rows are now of type :class:`OrderedDict`.
|
Returned rows are now of type :class:`OrderedDict`.
|
||||||
|
|
||||||
|
@ -209,6 +211,8 @@ The :mod:`csv` module defines the following classes:
|
||||||
Note that unlike the :class:`DictReader` class, the *fieldnames* parameter
|
Note that unlike the :class:`DictReader` class, the *fieldnames* parameter
|
||||||
of the :class:`DictWriter` class is not optional.
|
of the :class:`DictWriter` class is not optional.
|
||||||
|
|
||||||
|
If the argument passed to *fieldnames* is an iterator, it will be coerced to a :class:`list`.
|
||||||
|
|
||||||
A short usage example::
|
A short usage example::
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
|
|
|
@ -81,6 +81,8 @@ register_dialect("unix", unix_dialect)
|
||||||
class DictReader:
|
class DictReader:
|
||||||
def __init__(self, f, fieldnames=None, restkey=None, restval=None,
|
def __init__(self, f, fieldnames=None, restkey=None, restval=None,
|
||||||
dialect="excel", *args, **kwds):
|
dialect="excel", *args, **kwds):
|
||||||
|
if fieldnames is not None and iter(fieldnames) is fieldnames:
|
||||||
|
fieldnames = list(fieldnames)
|
||||||
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
|
||||||
self.restval = restval # default value for short rows
|
self.restval = restval # default value for short rows
|
||||||
|
@ -133,6 +135,8 @@ class DictReader:
|
||||||
class DictWriter:
|
class DictWriter:
|
||||||
def __init__(self, f, fieldnames, restval="", extrasaction="raise",
|
def __init__(self, f, fieldnames, restval="", extrasaction="raise",
|
||||||
dialect="excel", *args, **kwds):
|
dialect="excel", *args, **kwds):
|
||||||
|
if fieldnames is not None and iter(fieldnames) is fieldnames:
|
||||||
|
fieldnames = list(fieldnames)
|
||||||
self.fieldnames = fieldnames # list of keys for the dict
|
self.fieldnames = fieldnames # list of keys for the dict
|
||||||
self.restval = restval # for writing short dicts
|
self.restval = restval # for writing short dicts
|
||||||
if extrasaction.lower() not in ("raise", "ignore"):
|
if extrasaction.lower() not in ("raise", "ignore"):
|
||||||
|
|
|
@ -736,6 +736,34 @@ class TestDictFields(unittest.TestCase):
|
||||||
csv.DictWriter.writerow(writer, dictrow)
|
csv.DictWriter.writerow(writer, dictrow)
|
||||||
self.assertEqual(fileobj.getvalue(), "1,2\r\n")
|
self.assertEqual(fileobj.getvalue(), "1,2\r\n")
|
||||||
|
|
||||||
|
def test_dict_reader_fieldnames_accepts_iter(self):
|
||||||
|
fieldnames = ["a", "b", "c"]
|
||||||
|
f = StringIO()
|
||||||
|
reader = csv.DictReader(f, iter(fieldnames))
|
||||||
|
self.assertEqual(reader.fieldnames, fieldnames)
|
||||||
|
|
||||||
|
def test_dict_reader_fieldnames_accepts_list(self):
|
||||||
|
fieldnames = ["a", "b", "c"]
|
||||||
|
f = StringIO()
|
||||||
|
reader = csv.DictReader(f, fieldnames)
|
||||||
|
self.assertEqual(reader.fieldnames, fieldnames)
|
||||||
|
|
||||||
|
def test_dict_writer_fieldnames_rejects_iter(self):
|
||||||
|
fieldnames = ["a", "b", "c"]
|
||||||
|
f = StringIO()
|
||||||
|
writer = csv.DictWriter(f, iter(fieldnames))
|
||||||
|
self.assertEqual(writer.fieldnames, fieldnames)
|
||||||
|
|
||||||
|
def test_dict_writer_fieldnames_accepts_list(self):
|
||||||
|
fieldnames = ["a", "b", "c"]
|
||||||
|
f = StringIO()
|
||||||
|
writer = csv.DictWriter(f, fieldnames)
|
||||||
|
self.assertEqual(writer.fieldnames, fieldnames)
|
||||||
|
|
||||||
|
def test_dict_reader_fieldnames_is_optional(self):
|
||||||
|
f = StringIO()
|
||||||
|
reader = csv.DictReader(f, fieldnames=None)
|
||||||
|
|
||||||
def test_read_dict_fields(self):
|
def test_read_dict_fields(self):
|
||||||
with TemporaryFile("w+", encoding="utf-8") as fileobj:
|
with TemporaryFile("w+", encoding="utf-8") as fileobj:
|
||||||
fileobj.write("1,2,abc\r\n")
|
fileobj.write("1,2,abc\r\n")
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
The constructors for :class:`~csv.DictWriter` and :class:`~csv.DictReader` now coerce the ``fieldnames`` argument to a :class:`list` if it is an iterator.
|
Loading…
Add table
Add a link
Reference in a new issue