python 如何将“从未等待的协程”作为例外处理?

cbjzeqam  于 2023-03-16  发布在  Python
关注(0)|答案(1)|浏览(156)

关于如何忽略或解决这个问题有很多答案,但我需要的是一个解决方案,将处理这些,因为我们有一个巨大的项目,像这样的事情肯定会发生,但它是沉默的,因此在一段时间内被忽视。
我希望在这种情况发生时调用某个函数,或者引发一个异常(没有等待某个协程)。
我试着按照ChatGPT的建议添加以下内容,但没有效果:

# Set the warning mode to 'error'
import warnings
warnings.simplefilter('error', RuntimeWarning)

它现在所做的就是控制台说:

"Exception ignored in: <coroutine object XXX at 0x7fbca2e4eb90>

仍然没有异常,也没有办法捕捉和响应此错误。

dffbzjpn

dffbzjpn1#

主要的问题是,只有当协程本身超出作用域时才会发生这种情况--通常是在程序结束时(或者,在架构中包含的某个“重置阶段”),循环被关闭。
当在代码中发现对协同例程的调用时,如果存在对它的引用,则不会引发错误。由于通常希望从协同例程取回返回值,因此忘记了await只是将协同例程本身存储在应该包含结果的变量中,但它不会引发错误。在链接器和类似的工具上应该很容易捕获-甚至静态类型检查-但在运行时可能很难。
既然你希望在异常被引发时有一个“回调”--也许我们可以看一下警告代码,看看引发异常的代码是否可以在运行时打补丁来进行回调。普通的Python异常没有办法被系统范围的钩子捕获(除非当异常在运行时根本没有被处理时有一个程序范围的钩子--事实并非如此。因为asyncio循环 do handle 在本例中引发的RuntimeWarning用于打印Exception ignored消息。
但是通常不会发出警告--它们是通过调用warnings中的API发出的--这是Python代码,可以在运行时修改。
事实证明,如果warning保留默认值,并且没有改变为作为error出现,Python warnings机制会首先将其 Package 在warnings.WarningMessage示例中,可以挂钩到warning模块,用一个会影响所需回调的类替换这个类,并在运行时打补丁(“monkey patch”)。
因此,您可以编写如下所示的类,然后运行以下代码行,将回调框架植入警告机制:

import warnings

OriginalMessage = warnings.WarningMessage)

class HookableWarningMessage(warnings.WarningMessage):
     callback_registry = {}
     def __init__(self, *args, **kw):
          super().__init__(*args, **kw)
          self._check_callback()

     def _check_callback(self):
         if isinstance(self.message, RuntimeWarning):
              return
         for arg in self.message.args:
             for key in self.registry:
                  if key in arg:
                      self.registry[key](self,message)
     def register(self, pattern, target):
           self.registry[pattern] = target

warnings.WarningMessage = HookableWarningMessage

def not_awaited_coroutine_callback(RuntimeWarning):
    ...

warnings.WarningMessage.register("never awaited", not_waited_coroutine_callback)

相关问题