显示返回过时返回格式的例程的文件名和行号的警告

问题描述 投票:0回答:1

当我创建了一个库,其中的函数或方法将被弃用时,我可以警告用户 使用

warnings.warn(message, PendingDeprecationsWarning)
的事实库。通过设置
stacklevel
参数为
warnings.warn
适当地,我可以让警告引用要弃用的函数的调用位置,这对库的用户来说提供了更多信息。

但是我有一个基于插件的系统,它调用用户提供的插件类的

.status
方法。 status 方法用于返回
dict
,但该方法将被弃用 赞成返回一个
list
(这是对实际情况的简化)。 在这种情况下,警告对于提供插件的用户来说没有用:

import os, sys
from pathlib import Path
from importlib import import_module
import warnings
warnings.simplefilter('once', PendingDeprecationWarning)


class Driver:
    def __init__(self):
        self.plug_ins = []

    def load_plug_ins(self):
        sys.path.append('plug_ins')
        for file_name in Path('plug_ins').glob('p*.py'):
            mod = import_module(file_name.stem) 
            self.plug_ins.append(mod.PlugIn())

    def check_status(self):
        for p in self.plug_ins:
            retval = p.status()
            if isinstance(retval, dict):
                # assume dict
                warnings.warn('status() should return list, not dict', PendingDeprecationWarning)
            else:
                pass  # assume list

# create some plug-ins
Path('plug_ins/p0.py').write_text("""\
class PlugIn:
    def status(self):
        return {'result': 'ok'}
""")
Path('plug_ins/p1.py').write_text("""\
class PlugIn:
    def status(self):
        return ['ok'] # this plug-in has been updated
""")
Path('plug_ins/p2.py').write_text("""\
class PlugIn:
    def status(self):
        return {'result': 'ok'}
""")


driver = Driver()
driver.load_plug_ins()
for idx in range(2):
    driver.check_status()

给出:

/tmp/ryd-115/tmp_00.py:23: PendingDeprecationWarning: status() should return list, not dict
  warnings.warn('status() should return list, not dict', PendingDeprecationWarning)

输出中的路径和行号来自定义了驱动程序类的文件。 我想要显示的是定义

status
的文件的实际路径,以及该方法的行号,以及每个需要更新的文件(
p0.py
p2.py
)一次。

我怎样才能使用普通的Python警告系统(这样我就可以告诉用户使用普通的Python警告系统) 警告过滤以抑制消息)并显示

status
方法的文件名和行 需要更新,而不是显示文件名和代码中警告所在的行?

python plugins warnings
1个回答
0
投票

您必须修改

warnings.formatwarning
以获取警告 您调用,因此您需要定义一个警告以传递给
warnings.warn
。 如果您创建更多具有警告子类的警告,那么所有其他警告都派生自该警告子类,这是有意义的。

消息打印一次,要求它是可散列的,并且 而不是字符串作为

warnings.warn
的第一个参数,您可以 提供一个元组(然后在
formatwarning
中解压):

import os, sys
from pathlib import Path
from importlib import import_module
import warnings

class PlugInPendingDeprecationWarning(PendingDeprecationWarning):
    pass

# warn once on all PlugIn deprecations
warnings.simplefilter('once', PlugInPendingDeprecationWarning)

warnings.org_formatwarning = warnings.formatwarning
def my_formatwarning(message, category, filename, lineno, line):
    if isinstance(message, PlugInPendingDeprecationWarning):
        try:
            message, filename, lineno = message.args[0]
        except Exception as e:  # in case there was no tuple provided
            pass
    return warnings.org_formatwarning(message, category, filename, lineno, line)
warnings.formatwarning = my_formatwarning


class DictReturnPendingDeprecationWarning(PlugInPendingDeprecationWarning):
    pass

class Driver:
    def __init__(self):
        self.plug_ins = []

    def load_plug_ins(self):
        sys.path.append('plug_ins')
        for file_name in Path('plug_ins').glob('p*.py'):
            mod = import_module(file_name.stem) 
            self.plug_ins.append(mod.PlugIn())

    def check_status(self):
        for p in self.plug_ins:
            retval = p.status()
            if isinstance(retval, dict):
                # assume dict
                code = p.status.__func__.__code__
                warnings.warn(
                   ('callable should return list, not dict', code.co_filename, code.co_firstlineno),
                   DictReturnPendingDeprecationWarning,
                )
            else:
                pass  # assume list

driver = Driver()
driver.load_plug_ins()
for idx in range(2):
    driver.check_status()

给出:

/Users/anthon/src/se/so_q_000/plug_ins/p0.py:2: DictReturnPendingDeprecationWarning: callable should return list, not dict
  def status(self):
/Users/anthon/src/se/so_q_000/plug_ins/p2.py:2: DictReturnPendingDeprecationWarning: callable should return list, not dict
  def status(self):

您应该能够导入

PlugInPendingDeprecationWarning
(可能将其定义在单独的文件中 并将其导入您的驱动程序代码中), 然后让您的用户这样做:

import warnings
from somefile import PlugInPendingDeprecationWarning
warnings.simplefilter('ignore', PlugInPendingDeprecationWarning)

在他们的插件中,但它当然也会影响所有其他插件。

© www.soinside.com 2019 - 2024. All rights reserved.