From 8e139fcf5304d8a8cceaae9b4e829b891d05bf60 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 2 May 2020 19:27:47 +0200 Subject: [PATCH 1/2] Don't insert spurious newlines in DummyTqdmFile. Only call `tqdm.write` (which inserts a newline) if `DummyTqdmFile.write` is itself called with a string containing a newline; otherwise buffer the rest of the string. See changes in test_tqdm.py for the patterns this allows. --- tests/tests_tqdm.py | 9 ++++++++- tqdm/contrib/__init__.py | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/tests/tests_tqdm.py b/tests/tests_tqdm.py index dd33cc502..56033fef9 100644 --- a/tests/tests_tqdm.py +++ b/tests/tests_tqdm.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Advice: use repr(our_file.read()) to print the full output of tqdm # (else '\r' will replace the previous lines and you'll see only the latest. +from __future__ import print_function import csv import os @@ -1722,8 +1723,14 @@ def test_file_redirection(): with closing(StringIO()) as our_file: # Redirect stdout to tqdm.write() with std_out_err_redirect_tqdm(tqdm_file=our_file): - for _ in trange(3): + with tqdm(total=3) as pbar: print("Such fun") + pbar.update(1) + print("Such", "fun") + pbar.update(1) + print("Such ", end="") + print("fun") + pbar.update(1) res = our_file.getvalue() assert res.count("Such fun\n") == 3 assert "0/3" in res diff --git a/tqdm/contrib/__init__.py b/tqdm/contrib/__init__.py index f9dfa1713..f0b80c2a1 100644 --- a/tqdm/contrib/__init__.py +++ b/tqdm/contrib/__init__.py @@ -16,10 +16,19 @@ class DummyTqdmFile(ObjectWrapper): """Dummy file-like that will write to tqdm""" + def __init__(self, wrapped): + super(DummyTqdmFile, self).__init__(wrapped) + self._buf = [] + def write(self, x, nolock=False): - # Avoid print() second call (useless \n) - if len(x.rstrip()) > 0: - tqdm.write(x, file=self._wrapped, nolock=nolock) + nl = "\n" if isinstance(x, str) else b"\n" + pre, sep, post = x.rpartition(nl) + if sep: + tqdm.write(type(nl)().join(self._buf) + pre, + file=self._wrapped, nolock=nolock) + self._buf = [post] + else: + self._buf.append(x) def builtin_iterable(func): From d6495760a7b17266bce98673e5fee9c6a349e77a Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Wed, 17 Feb 2021 11:54:22 +0000 Subject: [PATCH 2/2] more DummyTqdmFile safety --- tqdm/contrib/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tqdm/contrib/__init__.py b/tqdm/contrib/__init__.py index f0b80c2a1..8a6d2474c 100644 --- a/tqdm/contrib/__init__.py +++ b/tqdm/contrib/__init__.py @@ -21,15 +21,24 @@ def __init__(self, wrapped): self._buf = [] def write(self, x, nolock=False): - nl = "\n" if isinstance(x, str) else b"\n" + nl = b"\n" if isinstance(x, bytes) else "\n" pre, sep, post = x.rpartition(nl) if sep: - tqdm.write(type(nl)().join(self._buf) + pre, - file=self._wrapped, nolock=nolock) + blank = type(nl)() + tqdm.write(blank.join(self._buf + [pre, sep]), + end=blank, file=self._wrapped, nolock=nolock) self._buf = [post] else: self._buf.append(x) + def __del__(self): + if self._buf: + blank = type(self._buf[0])() + try: + tqdm.write(blank.join(self._buf), end=blank, file=self._wrapped) + except (OSError, ValueError): + pass + def builtin_iterable(func): """Wraps `func()` output in a `list()` in py2"""