tqdm/tqdm

`DummyTqdmFile.write` cannot handle bytes type

marinelay opened this issue · 0 comments

  • I have marked all applicable categories:
    • exception-raising bug
    • visual output bug
  • I have visited the source website, and in particular
    read the known issues
  • I have searched through the issue tracker for duplicates
  • I have mentioned version numbers, operating system and
    environment, where applicable:
    import tqdm, sys
    print(tqdm.__version__, sys.version, sys.platform)

tqdm: 4.66
Python: 3.9.18
[GCC 9.4.0] linux

import contextlib
import sys
from tqdm import tqdm
from tqdm.contrib import DummyTqdmFile


@contextlib.contextmanager
def std_out_err_redirect_tqdm():
    orig_out_err = sys.stdout, sys.stderr
    try:
        sys.stdout, sys.stderr = map(DummyTqdmFile, orig_out_err)
        yield orig_out_err[0]
    # Relay exceptions
    except Exception as exc:
        raise exc
    # Always restore sys.stdout/err if necessary
    finally:
        sys.stdout, sys.stderr = orig_out_err

def some_fun(i):
    print("Fee, fi, fo,".split()[i])

# Redirect stdout to tqdm.write() (don't forget the `as save_stdout`)
with std_out_err_redirect_tqdm() as orig_stdout:
    sys.stdout.write(b"I'm being redirected to `tqdm.write()`\n")

Output :

Traceback (most recent call last):
  File "./tqdm/my_test.py", line 42, in <module>
    sys.stdout.write(b"I'm being redirected to `tqdm.write()`\n")
  File "./tqdm/tqdm/contrib/__init__.py", line 28, in write
    tqdm.write(blank.join(self._buf + [pre, sep]),
  File "./tqdm/tqdm/std.py", line 722, in write
    fp.write(s)
TypeError: write() argument must be str, not bytes

When redirecting sys.stdout to DummyTqdmFile.write, I believed that DummyTqdmFile.write could handle bytes type, but it raises TypeError: write() argument must be str, not bytes.

In the tqdm.contrib.__init__ source code,

def write(self, x, nolock=False):
nl = b"\n" if isinstance(x, bytes) else "\n"
pre, sep, post = x.rpartition(nl)
if sep:
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)

DummyTqdmFile.write handles bytes type obviously at line 24, so it is the reason why I think such that.
However, it raises TypeError because fp.write(s) ("./tqdm/tqdm/std.py", line 722) only accepts string type.

I think this bug can be fixed in two ways:
(1) Disallow bytes type in DummyTqdmFile.write
(2) Casting bytes to string before calling fp.write(s)

Thank you!