https://github.com/python/cpython/commit/0bc65955825e404ae74c780daf289528cae357e0 commit: 0bc65955825e404ae74c780daf289528cae357e0 branch: 3.13 author: Serhiy Storchaka <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-07-21T06:04:22Z summary:
[3.13] gh-103925: Fix csv.Sniffer for a quoted field ending a CRLF line (GH-103926) (GH-154330) "$" does not match before "\r" even in the MULTILINE mode, so such a field was not found and the delimiter was guessed from character frequencies instead, which could give a letter. (cherry picked from commit 70f7c6c0f2ddfd3b447946f1b926776b2a344703) Co-authored-by: Zhou Wei <[email protected]> files: A Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst M Lib/csv.py M Lib/test/test_csv.py diff --git a/Lib/csv.py b/Lib/csv.py index cd202659873811..b73ad049d98166 100644 --- a/Lib/csv.py +++ b/Lib/csv.py @@ -283,10 +283,10 @@ def _guess_quote_and_delimiter(self, data, delimiters): """ matches = [] - for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?", - r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?", - r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\n)', # ,".*?" - r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\n)'): # ".*?" (no delim, no space) + for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?", + r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)', # ".*?", + r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)', # ,".*?" + r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)'): # ".*?" (no delim, no space) regexp = re.compile(restr, re.DOTALL | re.MULTILINE) matches = regexp.findall(data) if matches: diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 6ea388313bbfd4..b6e578c40e7471 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -1357,6 +1357,9 @@ class TestSniffer(unittest.TestCase): ghi\0jkl """ + sample19 = ('time,title\r\n' + '2020-10-01,"Pocket - Save news, videos, stories and more"\r\n') + def test_issue43625(self): sniffer = csv.Sniffer() self.assertTrue(sniffer.has_header(self.sample12)) @@ -1427,6 +1430,9 @@ def test_delimiters(self): self.assertEqual(dialect.quotechar, "'") dialect = sniffer.sniff(self.sample14) self.assertEqual(dialect.delimiter, '\0') + dialect = sniffer.sniff(self.sample19) + self.assertEqual(dialect.delimiter, ',') + self.assertEqual(dialect.quotechar, '"') def test_doublequote(self): sniffer = csv.Sniffer() diff --git a/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst b/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst new file mode 100644 index 00000000000000..858ce6e5bd98e7 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst @@ -0,0 +1,3 @@ +Fix :meth:`csv.Sniffer.sniff` for a sample with ``\r\n`` line endings in +which a quoted field ends a line: a letter could be detected as the +delimiter. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
