From 7a5e8341237c539ff9b8bdd51ff568d822e015b8 Mon Sep 17 00:00:00 2001 From: David Wales Date: Sat, 7 May 2022 12:30:07 +1000 Subject: [PATCH] Use newline='' for csv.writer (#1368) Fixes #1362 According to the docs for csv.writer: > If csvfile is a file object, it should be opened with newline='' > https://docs.python.org/3/library/csv.html#csv.writer Additionally: > If newline='' is not specified, newlines embedded inside quoted fields will > not be interpreted correctly, and on platforms that use \r\n linendings on > write an extra \r will be added. It should always be safe to specify > newline='', since the csv module does its own (universal) newline handling. > https://docs.python.org/3/library/csv.html#id3 This commit adds `newline=None` as a keyword argument for `open_text` in `path.py`. It then uses this new keyword argument when opening a file for writing in `loaders/csv.py` --- visidata/loaders/csv.py | 2 +- visidata/path.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/visidata/loaders/csv.py b/visidata/loaders/csv.py index bfd4e85a9..d74d017ec 100644 --- a/visidata/loaders/csv.py +++ b/visidata/loaders/csv.py @@ -47,7 +47,7 @@ def iterload(self): @VisiData.api def save_csv(vd, p, sheet): 'Save as single CSV file, handling column names as first line.' - with p.open_text(mode='w', encoding=sheet.options.encoding) as fp: + with p.open_text(mode='w', encoding=sheet.options.encoding, newline='') as fp: cw = csv.writer(fp, **options.getall('csv_')) colnames = [col.name for col in sheet.visibleCols] if ''.join(colnames): diff --git a/visidata/path.py b/visidata/path.py index 4b7245ab2..bdae107ba 100644 --- a/visidata/path.py +++ b/visidata/path.py @@ -159,7 +159,7 @@ def __lt__(self, a): def __truediv__(self, a): return Path(self._path.__truediv__(a)) - def open_text(self, mode='rt', encoding=None): + def open_text(self, mode='rt', encoding=None, newline=None): 'Open path in text mode, using options.encoding and options.encoding_errors. Return open file-pointer or file-pointer-like.' # rfile makes a single-access fp reusable @@ -183,7 +183,7 @@ def open_text(self, mode='rt', encoding=None): vd.error('invalid mode "%s" for Path.open_text()' % mode) return sys.stderr - return self.open(mode=mode, encoding=encoding or vd.options.encoding, errors=vd.options.encoding_errors) + return self.open(mode=mode, encoding=encoding or vd.options.encoding, errors=vd.options.encoding_errors, newline=newline) @wraps(pathlib.Path.read_text) def read_text(self, *args, **kwargs):