]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-76728: Coerce DictReader and DictWriter fieldnames argument to a list (GH-32225)
authorSam Ezeh <sam.z.ezeh@gmail.com>
Thu, 25 Aug 2022 10:13:24 +0000 (11:13 +0100)
committerGitHub <noreply@github.com>
Thu, 25 Aug 2022 10:13:24 +0000 (05:13 -0500)
Doc/library/csv.rst
Lib/csv.py
Lib/test/test_csv.py
Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst [new file with mode: 0644]

index 9dec7240d9c50fdecd4ad9ac7738b029f178f2c2..0cab95e1500a6659c5821fea41dc57bc8b1591c7 100644 (file)
@@ -167,6 +167,8 @@ The :mod:`csv` module defines the following classes:
    All other optional or keyword arguments are passed to the underlying
    :class:`reader` instance.
 
+   If the argument passed to *fieldnames* is an iterator, it will be coerced to a :class:`list`.
+
    .. versionchanged:: 3.6
       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
    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::
 
        import csv
index bfc850ee96dab6fffad499bcf1f995ea03c1ca26..0de5656a4eed7ba11d573b81f0031106653698d9 100644 (file)
@@ -81,6 +81,8 @@ register_dialect("unix", unix_dialect)
 class DictReader:
     def __init__(self, f, fieldnames=None, restkey=None, restval=None,
                  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.restkey = restkey          # key to catch long rows
         self.restval = restval          # default value for short rows
@@ -133,6 +135,8 @@ class DictReader:
 class DictWriter:
     def __init__(self, f, fieldnames, restval="", extrasaction="raise",
                  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.restval = restval          # for writing short dicts
         if extrasaction.lower() not in ("raise", "ignore"):
index 95a19dd46cb4ffa1dfbceb7d571f44c3aebee234..51ca1f2ab29285428a1cab84e17d84e2750944b6 100644 (file)
@@ -736,6 +736,34 @@ class TestDictFields(unittest.TestCase):
         csv.DictWriter.writerow(writer, dictrow)
         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):
         with TemporaryFile("w+", encoding="utf-8") as fileobj:
             fileobj.write("1,2,abc\r\n")
diff --git a/Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst b/Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst
new file mode 100644 (file)
index 0000000..4599b73
--- /dev/null
@@ -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.