for i, row in enumerate(csv.reader(fileobj)):
self.assertEqual(row, rows[i])
+ def test_roundtrip_escaped_unquoted_newlines(self):
+ with TemporaryFile("w+", newline='') as fileobj:
+ writer = csv.writer(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")
+ rows = [['a\nb','b'],['c','x\r\nd']]
+ writer.writerows(rows)
+ fileobj.seek(0)
+ for i, row in enumerate(csv.reader(fileobj,quoting=csv.QUOTE_NONE,escapechar="\\")):
+ self.assertEqual(row,rows[i])
+
class TestDialectRegistry(unittest.TestCase):
def test_registry_badargs(self):
self.assertRaises(TypeError, csv.list_dialects, None)
Library
-------
+- Issue #15927: CVS now correctly parses escaped newlines and carriage
+ when parsing with quoting turned off.
+
- Issue #17467: add readline and readlines support to mock_open in
unittest.mock.
typedef enum {
START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD,
IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD,
- EAT_CRNL
+ EAT_CRNL,AFTER_ESCAPED_CRNL
} ParserState;
typedef enum {
break;
case ESCAPED_CHAR:
+ if (c == '\n' | c=='\r') {
+ if (parse_add_char(self, c) < 0)
+ return -1;
+ self->state = AFTER_ESCAPED_CRNL;
+ break;
+ }
if (c == '\0')
c = '\n';
if (parse_add_char(self, c) < 0)
self->state = IN_FIELD;
break;
+ case AFTER_ESCAPED_CRNL:
+ if (c == '\0')
+ break;
+ /*fallthru*/
+
case IN_FIELD:
/* in unquoted field */
if (c == '\n' || c == '\r' || c == '\0') {