在 Python 中使用可选导入进行测试
Testing with Optional Import in Python
我有一个可以使用两个模块的库;一个速度很快但仅在 Linux 和 macOS 上可用,另一个速度较慢但它是多平台的。我的解决方案是使库与两者兼容并具有如下内容:
try:
import fastmodule
except ImportError:
import slowmodule
现在我想比较使用任一模块时库的时序。在安装了两个模块的环境中,是否有任何方法可以在不更改源代码(即在 Jupyter Notebook 中)的情况下屏蔽 fastmodule
,以便使用 slowmodule
?
这有点乱七八糟,但就是这样:
您可以编写自己的导入器并注册它(请注意,这是 Python 3 特定的,Python 2 有另一个 API 用于此):
import sut
import functools
import importlib
import sys
def use_slow(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
ImportRaiser.use_slow = True
if 'fastmodule' in sys.modules:
del sys.modules['fastmodule'] # otherwise it will remain cached
importlib.reload(sut)
f(*args, **kwargs)
return wrapped
def use_fast(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
ImportRaiser.use_slow = False
importlib.reload(sut)
f(*args, **kwargs)
return wrapped
class ImportRaiser:
use_slow = False
def find_spec(self, fullname, path, target=None):
if fullname == 'fastmodule':
if self.use_slow:
raise ImportError()
sys.meta_path.insert(0, ImportRaiser())
@use_fast
def test_fast():
# test code
@use_slow
def test_slow():
# test code
这里,sut
是您正在测试的模块,您必须重新加载它才能更改行为。我为可读性添加了装饰器,但这当然可以通过某些函数或在测试设置中完成。
如果您使用慢速版本,fastmodule
将在导入时提高 ImportError
并且将使用 slowmodule
代替。在 "fast" 情况下,一切正常。
我有一个可以使用两个模块的库;一个速度很快但仅在 Linux 和 macOS 上可用,另一个速度较慢但它是多平台的。我的解决方案是使库与两者兼容并具有如下内容:
try:
import fastmodule
except ImportError:
import slowmodule
现在我想比较使用任一模块时库的时序。在安装了两个模块的环境中,是否有任何方法可以在不更改源代码(即在 Jupyter Notebook 中)的情况下屏蔽 fastmodule
,以便使用 slowmodule
?
这有点乱七八糟,但就是这样:
您可以编写自己的导入器并注册它(请注意,这是 Python 3 特定的,Python 2 有另一个 API 用于此):
import sut
import functools
import importlib
import sys
def use_slow(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
ImportRaiser.use_slow = True
if 'fastmodule' in sys.modules:
del sys.modules['fastmodule'] # otherwise it will remain cached
importlib.reload(sut)
f(*args, **kwargs)
return wrapped
def use_fast(f):
@functools.wraps(f)
def wrapped(*args, **kwargs):
ImportRaiser.use_slow = False
importlib.reload(sut)
f(*args, **kwargs)
return wrapped
class ImportRaiser:
use_slow = False
def find_spec(self, fullname, path, target=None):
if fullname == 'fastmodule':
if self.use_slow:
raise ImportError()
sys.meta_path.insert(0, ImportRaiser())
@use_fast
def test_fast():
# test code
@use_slow
def test_slow():
# test code
这里,sut
是您正在测试的模块,您必须重新加载它才能更改行为。我为可读性添加了装饰器,但这当然可以通过某些函数或在测试设置中完成。
如果您使用慢速版本,fastmodule
将在导入时提高 ImportError
并且将使用 slowmodule
代替。在 "fast" 情况下,一切正常。