在运行测试或通过cron运行代码时,如何使tqdm的输出静音?

81
我正在使用 tqdm 来在完成一些长时间运行的 Django 管理命令时显示进度条。它非常好用,但是当我在代码上运行单元测试时,我希望停止输出进度条。如果我使用 cron 或其他方式在后台运行这些命令,我也希望不要输出进度条。我没有找到简单的方法来实现这两个需求,也许我有所遗漏?
6个回答

83

使用“disable”参数的示例:

from tqdm import tqdm
import time

for i in tqdm(range(10), disable=True):
    time.sleep(1)

2
这是一个非常好的答案,截至2021年1月,它完美地发挥作用。 - Yannik Suhre

64

有一个disable参数,你可以将它设置为True来禁止任何tqdm输出(实际上,它将完全跳过进度条计算,而不仅仅是显示)。

要动态切换它,你可以向脚本添加一个命令行参数,以定义是否设置了disable。这对单元测试和cron都适用。


1
你如何在保持计算的同时禁用显示? - Austin
1
@Austin 你是指进度条的计算吗?没有办法,但如果你不显示它,那有什么意义呢?只要通过禁用“disable”参数恢复显示,进度条的计算就会恢复。但无论如何,你的应用程序的计算都不会受到任何影响,只有用于显示的进度条计算被禁用了。 - gaborous

64

这是一个非常常见的用例,当您需要全局禁用所有 tqdm 的输出时,最好不要更改使用它的所有地方的代码,而且您可能无法控制。

从版本4.66.0开始

设置环境变量 TQDM_DISABLE=1。 注意,变量的确切值并不重要,只需是非空字符串即可。

旧版本

用户需要修补 tqdm 以阻止污染日志。我找到的最简短的方法之一可能是这样:

from tqdm import tqdm
from functools import partialmethod

tqdm.__init__ = partialmethod(tqdm.__init__, disable=True)

这个想法是将初始化器的已支持(但不足够)参数默认化。它不足够,因为你需要在每个实例化tqdm的地方添加它,而你并不希望这样做,这就是为什么我们修改了__init__以创建这样一个默认值。

这个补丁与导入的顺序无关,并且会影响所有随后创建的tqdm对象。


2
我刚试过了,使用tqdm导入的包可以正常工作,而且完全不需要修改或重写代码。 - Lars Ericson
1
这对于处理带有tqdm语句的外部依赖关系非常有用,你不希望这些语句填满你试图监视的日志。 - colby-ham
1
这是一个完美的答案。你既不需要改变现有的代码,也不需要添加任何布尔标志来传递。我只是将它添加到我的testing_main.py的开头,它就可以禁用测试环境中的所有tqdm输出了。 - Berkay Berabi
1
这很完美,将其添加到tests/__init__.py中,然后您就可以继续进行了。 - David258
如果这对你不起作用,请确保你在from tqdm import tqdm上使用它,而不是仅在import tqdm上使用它;) - Cnly
此外,如果这对您不起作用,请检查相应的模块是否实际上使用了 from tqdm import tqdm,它也可以是 from tqdm.auto import tqdm - Eloy Pérez Torres

9

使用mock.patch替换代码中正在使用的tqdm,可以像这样进行替换:

def notqdm(iterable, *args, **kwargs):
    """
    replacement for tqdm that just passes back the iterable
    useful to silence `tqdm` in tests
    """
    return iterable

同时在测试中:

import mock

...

    @mock.patch('tested_code_module.tqdm', notqdm)
    def test_method(self):
    ...

2

版本4.66.0以来,可以使用环境变量覆盖默认tqdm参数,环境变量需要以TQDM_前缀和参数名称结尾。这意味着您可以在导入tqdm或任何使用它的模块之前,通过将TQDM_DISABLE环境变量设置为1来禁用tqdm的输出:

import os

os.environ["TQDM_DISABLE"] = "1"

# import tqdm and/or modules that use it here

0
借鉴这个答案(谢谢!),如果你也使用tqdm.write,这段代码也可以用来抑制它们:
MODULE_TQDM = "tested_code_module.tqdm"

class NoTQDM:
    def __init__(self, iterable, *args, **kwargs):
        self.iterable = iterable

    def __iter__(self):
        for item in self.iterable:
            yield item

    def write(self, *args, **kwargs):
        pass

然后在测试中:
from unittest import mock

...

    @mock.patch(MODULE_TQDM, NoTQDM)
    def test_method(self):
    ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接