Redirecionar stdout e stderr com a biblioteca python tqdm

Estou usando o tqdm no Python para exibir as barras de progresso do console.

Eu tenho uma function de outra biblioteca que ocasionalmente grava em stdout e stderr dentro do loop tqdm. Eu não posso hackear o código fonte dessa function.

Embora este documento mostre como redirect sys.stdout, ele não é facilmente generalizado para stderr porque eu posso passar apenas um dos stdout ou stderr para o parâmetro file= no __init__ de tqdm. Por favor, consulte esta questão e sua resposta aceita para o código mínimo que ilustra o problema.

Como faço para redirect stdout e stderr juntos?

O Python fornece alguns helpers para você nas bibliotecas padrão, veja em contextlib :

 >>> import io, sys >>> from contextlib import redirect_stdout, redirect_stderr >>> from tqdm import tqdm >>> def foo(): ... print('spam to stdout') ... print('spam to stderr', file=sys.stderr) ... >>> out = io.StringIO() >>> err = io.StringIO() >>> with redirect_stdout(out), redirect_stderr(err): ... for x in tqdm(range(3), file=sys.__stdout__): ... print(x) # more spam ... foo() ... 100%|██████████| 3/3 [00:00<00:00, 29330.80it/s] >>> out.getvalue() '0\nspam to stdout\n1\nspam to stdout\n2\nspam to stdout\n' >>> err.getvalue() 'spam to stderr\nspam to stderr\nspam to stderr\n'