warnings ---报警控制

源代码: Lib/warnings.py


警告消息通常在以下情况下发出:警告用户程序中的某些情况(通常情况下)不需要引发异常并终止程序时,该情况很有用。例如,当程序使用过时的模块时,可能需要发出警告。

python程序员通过调用 warn() 此模块中定义的函数。(C程序员使用 PyErr_WarnEx()异常处理 详情请参阅。

警告消息通常写入 sys.stderr 但是他们的性格可以灵活地改变,从忽视所有的警告到把它们变成例外。警告的处理可能因 warning category ,警告消息的文本,以及发出警告消息的源位置。同一震源位置的特定警告重复通常被抑制。

警告控制分为两个阶段:第一,每次发出警告时,都要确定是否应发出消息;第二,如果要发出消息,则使用用户可设置的挂钩对其进行格式化和打印。

是否发出警告消息的决定由 warning filter ,这是一系列匹配的规则和操作。可以通过调用将规则添加到筛选器 filterwarnings() 并通过调用 resetwarnings() .

通过调用 showwarning() ,可以重写;此函数的默认实现通过调用 formatwarning() ,也可供自定义实现使用。

参见

logging.captureWarnings() 允许您使用标准日志记录基础结构处理所有警告。

警告类别

有许多表示警告类别的内置异常。此分类对于筛选出警告组很有用。

虽然从技术上来说 built-in exceptions ,它们被记录在这里,因为在概念上它们属于警告机制。

用户代码可以通过子类化标准警告类别之一来定义其他警告类别。警告类别必须始终是 Warning 类。

当前定义了以下警告类别类:

等级

描述

Warning

这是所有警告类别的基类。它是 Exception .

UserWarning

的默认类别 warn() .

DeprecationWarning

当这些警告用于其他Python开发人员时,有关已弃用功能的警告的基本类别(默认情况下忽略,除非由中的代码触发) __main__

SyntaxWarning

有关可疑语法特征的警告的基本类别。

RuntimeWarning

有关可疑运行时功能的警告的基本类别。

FutureWarning

当这些警告用于用Python编写的应用程序的最终用户时,有关已弃用功能的警告的基本类别。

PendingDeprecationWarning

有关将来将被弃用的功能的警告的基本类别(默认情况下忽略)。

ImportWarning

导入模块过程中触发的警告的基本类别(默认情况下忽略)。

UnicodeWarning

与Unicode相关的警告的基本类别。

BytesWarning

与相关警告的基本类别 bytesbytearray .

ResourceWarning

与资源使用有关的警告的基本类别。

在 3.7 版更改: 以前 DeprecationWarningFutureWarning 根据特征是否被完全删除或改变其行为来区分。它们现在根据预期的访问群体以及默认警告过滤器处理它们的方式进行区分。

警告过滤器

警告筛选器控制警告是被忽略、显示还是变成错误(引发异常)。

在概念上,警告过滤器维护过滤器规范的有序列表;任何特定的警告依次与列表中的每个过滤器规范匹配,直到找到匹配为止;过滤器确定匹配的处置。每个条目都是表单的元组( 行动消息类别模块林诺 ):

  • 行动 是以下字符串之一:

    价值

    性情

    "default"

    为发出警告的每个位置(模块+行号)打印第一次出现的匹配警告

    "error"

    将匹配的警告转换为异常

    "ignore"

    从不打印匹配的警告

    "always"

    始终打印匹配警告

    "module"

    为发出警告的每个模块打印第一次出现的匹配警告(不考虑行号)

    "once"

    只打印第一次出现的匹配警告,无论位置如何

  • 消息 包含警告消息开头必须匹配的正则表达式的字符串。该表达式被编译为始终不区分大小写。

  • 类别 是一个类(子类 Warning )其中警告类别必须是子类才能匹配。

  • 模块 是包含模块名称必须匹配的正则表达式的字符串。表达式被编译为区分大小写。

  • 林诺 是发生警告的行号必须匹配的整数,或者 0 匹配所有行号。

自从 Warning 类是从内置的 Exception 类,将警告转换为错误 category(message) .

如果报告了警告且与任何注册的筛选器都不匹配,则应用“默认”操作(因此而得名)。

描述警告筛选器

警告筛选器由初始化 -W 传递给python解释器命令行和 PYTHONWARNINGS 环境变量。解释器将所有提供的条目的参数保存在 sys.warnoptionswarnings 模块在第一次导入时对其进行分析(在将消息打印到 sys.stderr

单个警告筛选器被指定为用冒号分隔的字段序列:

action:message:category:module:line

每个字段的含义如中所述。 警告过滤器 . 在一行中列出多个筛选器时(例如 PYTHONWARNINGS ,各个过滤器用逗号分隔,后面列出的过滤器优先于前面列出的过滤器(因为它们从左到右应用,最近应用的过滤器优先于前面的过滤器)。

常用的警告筛选器适用于所有警告、特定类别中的警告或特定模块或包引发的警告。一些例子:

default                      # Show all warnings (even those ignored by default)
ignore                       # Ignore all warnings
error                        # Convert all warnings to errors
error::ResourceWarning       # Treat ResourceWarning messages as errors
default::DeprecationWarning  # Show DeprecationWarning messages
ignore,default:::mymodule    # Only report warnings triggered by "mymodule"
error:::mymodule[.*]         # Convert warnings to errors in "mymodule"
                             # and any subpackages of "mymodule"

默认警告筛选器

默认情况下,python安装了几个警告过滤器,这些过滤器可以被 -W 命令行选项 PYTHONWARNINGS 环境变量和调用 filterwarnings() .

在常规版本中,默认警告筛选器具有以下条目(按优先级顺序)::

default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning

在调试生成中,默认警告筛选器列表为空。

在 3.2 版更改: DeprecationWarning 默认情况下,除了 PendingDeprecationWarning .

在 3.7 版更改: DeprecationWarning 当由中的代码直接触发时,在默认情况下再次显示 __main__ .

在 3.7 版更改: BytesWarning 不再出现在默认筛选器列表中,而是通过 sys.warnoptions 什么时候? -b 指定了两次。

覆盖默认筛选器

用python编写的应用程序的开发人员可能希望隐藏 all 默认情况下,来自用户的Python级警告,并且仅在运行测试或以其他方式处理应用程序时显示这些警告。这个 sys.warnoptions 用于将筛选器配置传递给解释器的属性可以用作标记,以指示是否应禁用警告::

import sys

if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

建议针对python代码的测试运行程序的开发人员确保 all 默认情况下,将使用如下代码显示测试代码的警告:

import sys

if not sys.warnoptions:
    import os, warnings
    warnings.simplefilter("default") # Change the filter in this process
    os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses

最后,交互式shell的开发人员在命名空间之外运行用户代码 __main__ 建议确保 DeprecationWarning 消息在默认情况下是可见的,使用如下代码(其中 user_ns 模块是否用于执行交互式输入的代码)::

import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
                                   module=user_ns.get("__name__"))

暂时禁止警告

如果您使用的代码已知将引发警告,例如不推荐使用的函数,但不希望看到警告(即使已通过命令行显式配置了警告),则可以使用 catch_warnings 上下文管理器:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

在上下文管理器中,所有警告都将被忽略。这允许您使用已知的弃用代码,而不必看到警告,同时不禁止可能不知道其使用弃用代码的其他代码的警告。注意:这只能在单线程应用程序中得到保证。如果两个或多个线程使用 catch_warnings 上下文管理器同时,行为未定义。

测试警告

要测试代码引发的警告,请使用 catch_warnings 上下文管理器。使用它,您可以临时改变警告过滤器,以方便您的测试。例如,执行以下操作以捕获所有引发的要检查的警告::

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

通过使用 error instead of always. One thing to be aware of is that if a warning has already been raised because of a once/default 规则,则无论设置了什么筛选器,除非清除了与警告相关的警告注册表,否则不会再次看到警告。

一旦上下文管理器退出,警告筛选器将在输入上下文时恢复到其状态。这可以防止测试在测试之间以意外的方式更改警告过滤器,从而导致不确定的测试结果。这个 showwarning() 模块中的功能也会恢复到其原始值。注意:这只能在单线程应用程序中得到保证。如果两个或多个线程使用 catch_warnings 上下文管理器同时,行为未定义。

在测试引发同一类警告的多个操作时,重要的是要以确认每个操作都会引发新警告的方式对它们进行测试(例如,将要引发的警告设置为异常,并检查操作是否引发异常,在每次操作后检查警告列表的长度是否继续增加,否则,请检查D。在每次新操作之前从警告列表中删除以前的条目)。

正在更新依赖项的新版本的代码

默认情况下,忽略了主要是Python开发人员(而不是用Python编写的应用程序的最终用户)感兴趣的警告类别。

值得注意的是,这个“默认忽略”列表包括 DeprecationWarning (每个模块,除了 __main__ ,这意味着开发人员应该确保使用可见的通常被忽略的警告来测试他们的代码,以便及时收到未来破坏API更改的通知(无论是在标准库还是第三方包中)。

在理想情况下,代码将有一个合适的测试套件,测试运行程序将在运行测试(由 unittest 模块执行此操作)。

在不太理想的情况下,可以通过传递 -Wd 到python解释器(这是 -W default 或设置 PYTHONWARNINGS=default 在环境中。这将启用所有警告的默认处理,包括默认忽略的警告。要更改对遇到的警告采取的操作,可以更改传递给的参数 -W (例如) -W error )见 -W 有关可能发生的情况的详细信息的标志。

可用功能

warnings.warn(message, category=None, stacklevel=1, source=None)

发出警告,或者忽略它,或者引发异常。这个 类别 参数(如果给定)必须是 warning category class ;默认为 UserWarning . 或者, 消息 可以是 Warning 例如,在这种情况下 类别 将被忽略并且 message.__class__ 将被使用。在这种情况下,消息文本将 str(message) . 如果发出的特定警告被更改为错误, warnings filter . 这个 堆积层 参数可由用python编写的包装函数使用,如下所示:

def deprecation(message):
    warnings.warn(message, DeprecationWarning, stacklevel=2)

这使得警告参考 deprecation() 的调用方,而不是 deprecation() 自身(因为后者会破坏警告消息的目的)。

source 如果提供,则是发出 ResourceWarning .

在 3.6 版更改: 补充 source 参数。

warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)

这是一个低级接口,用于 warn() ,显式传递消息、类别、文件名和行号,以及可选的模块名和注册表(应该是 __warningregistry__ 模块字典)。模块名默认为 .py 已删除;如果未通过注册表,则不会取消警告。 消息 必须是字符串并且 类别 一个子类 Warning消息 可能是 Warning 例如,在这种情况下 类别 将被忽略。

module_globals 如果提供,则应为发出警告的代码所使用的全局命名空间。(此参数用于支持显示压缩文件或其他非文件系统导入源中的模块的源代码)。

source 如果提供,则是发出 ResourceWarning .

在 3.6 版更改: 添加 source 参数。

warnings.showwarning(message, category, filename, lineno, file=None, line=None)

将警告写入文件。默认实现调用 formatwarning(message, category, filename, lineno, line) 并将结果字符串写入 file ,默认为 sys.stderr . 可以将此函数替换为任何可调用函数,方法是将 warnings.showwarning . line 是要包含在警告消息中的源代码行;如果 line 未提供, showwarning() 将尝试读取指定的行 文件名林诺 .

warnings.formatwarning(message, category, filename, lineno, line=None)

以标准方式设置警告格式。这将返回一个字符串,该字符串可能包含嵌入的换行符并以换行符结尾。 line 是要包含在警告消息中的源代码行;如果 line 未提供, formatwarning() 将尝试读取指定的行 filename林诺 .

warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False)

在列表中插入一个条目 warnings filter specifications . 默认情况下,条目插入到前面;如果 追加 是真的,它被插入到末尾。这将检查参数的类型,编译 消息模块 正则表达式,并将它们作为元组插入到警告筛选器列表中。如果两个条目都符合特定警告,则靠近列表前面的条目将覆盖列表后面的条目。省略参数默认为匹配所有内容的值。

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

在列表中插入一个简单条目 warnings filter specifications . 函数参数的含义如下 filterwarnings() ,但不需要正则表达式,因为只要类别和行号匹配,插入的筛选器总是匹配任何模块中的任何消息。

warnings.resetwarnings()

重置警告筛选器。这将放弃以前对 filterwarnings() 包括 -W 命令行选项和调用 simplefilter() .

可用的上下文管理器

class warnings.catch_warnings(*, record=False, module=None)

一个上下文管理器,它复制并在退出时还原警告筛选器和 showwarning() 功能。如果 记录 论证是 False (默认)上下文管理器返回 None 进入时。如果 记录True ,将返回一个列表,该列表将逐步填充自定义所看到的对象。 showwarning() 函数(也抑制输出到 sys.stdout )列表中的每个对象都具有与参数具有相同名称的属性 showwarning() .

这个 模块 参数接受将在导入时使用的模块,而不是返回的模块 warnings 其过滤器将受到保护。此参数主要用于测试 warnings 模块本身。

注解

这个 catch_warnings 管理器的工作方式是替换模块,然后恢复模块的 showwarning() 过滤器规格的功能和内部列表。这意味着上下文管理器正在修改全局状态,因此不是线程安全的。