【问题标题】:Python unit testing: How to stop gevent.monkey.patch_all() affecting asyncio tests?Python 单元测试:如何停止影响异步测试的 gevent.monkey.patch_all()?
【发布时间】:2022-11-11 05:06:26
【问题描述】:
我们有一个 python 测试套件来测试使用gevent.monkey.patch_all() 的代码。测试运行良好。
在同一个代码库中,我们有一个使用asyncio 的替代入口点。也有一些测试,它们自己运行良好,使用这种设置:
import asyncio
from our_module import main
class AsyncioTests(unittest.TestCase):
"""Test some asyncio stuff."""
def test_something(self):
asyncio.run(main())
但是,如果它们在导入带有猴子补丁的模块的测试之后运行,它们将永远挂起。好像是因为猴子补丁。
有没有办法通过逆转猴子补丁来阻止这种情况?
【问题讨论】:
标签:
python-asyncio
python-unittest
gevent
monkeypatching
【解决方案1】:
我通过Gevent monkey unpatch 找到了这个https://emptysqua.re/blog/undoing-gevents-monkey-patching/,但这个建议没有奏效。似乎问题比一个模块更深一些(我也尝试过重新加载几个)。
但是,gevent.monkey 模块中有一个undocumented but public variable,称为saved:
# maps module name -> {attribute name: original item}
# e.g. "time" -> {"sleep": built-in function sleep}
# NOT A PUBLIC API. However, third-party monkey-patchers may be using
# it? TODO: Provide better API for them.
saved = {}
使用它,我可以撤消 gevent 在使用该代码的测试套件的 tearDownClass 中引入的所有补丁:
class SomeTests(unittest.TestCase):
"""Tests using code imported from a module gevent.monkey.patch_all'd."""
@classmethod
def tearDownClass(cls):
"""Undo monkeypatching so that other tests don't get stuck.
Note: this is needed because of asyncio.
"""
import importlib
from gevent import monkey
for modname in monkey.saved.keys():
try:
mod = __import__(modname)
importlib.reload(mod)
for key in monkey.saved[modname].keys():
setattr(mod, key, monkey.saved[modname][key])
except ImportError:
pass
好可怕……?也许...